Android Nougat: Detected problems with app native libraries - android

we just upgrade our Nexus 96 to Android N and now get the following popup while working with our app:
give me some suggestions

Check reported same issue:
https://github.com/litehelpers/Cordova-sqlcipher-adapter/issues/41
Now it has already been resolved.
For reference:
sqlcipher/android-database-sqlcipher#216
You can check SQLCipher for Android Release—Android N Support on below link:
https://discuss.zetetic.net/t/sqlcipher-for-android-release-android-n-support/1465
EDIT:
You can also check
NDK Apps Linking to Platform Libraries for private libraries usage.
Check "Update your app" section which provides steps to fix these types of errors.

You are probably using a native library that is directly accessing private APIs. The issue is described below.
From Android Developers Blog https://android-developers.googleblog.com/2016/06/android-changes-for-ndk-developers.html:
Private API (Enforced since API 24)
Native libraries must use only public API http://developer.android.com/ndk/guides/stable_apis.html?utm_campaign=android_discussion_ndkchanges_062716&utm_source=anddev&utm_medium=blog, and must not link against non-NDK platform libraries. Starting with API 24 this rule is enforced and applications are no longer able to load non-NDK platform libraries. The rule is enforced by the dynamic linker, so non-public libraries are not accessible regardless of the way code tries to load them: System.loadLibrary(...), DT_NEEDED entries, and direct calls to dlopen(...) will fail in exactly the same way.
(...)
Potential problems: starting from API 24 the dynamic linker will not load private libraries, preventing the application from loading.
Resolution: rewrite your native code to rely only on public API. As a short term workaround, platform libraries without complex dependencies (libcutils.so) can be copied to the project. As a long term solution the relevant code must be copied to the project tree. SSL/Media/JNI internal/binder APIs should not be accessed from the native code. When necessary, native code should call appropriate public Java API methods.
A complete list of public libraries is available within the NDK, under platforms/android-API/usr/lib.
As other answers pointed, it seems that this API 24 issue has been solved.

Related

How library packaging works in android

I have confusion that how the android packaging works with library, Say i am used some kotlin experimental apis in my application.I have published the application, Say After the production the experimental api which i have used have major change.
Does my app which is already published get affected?
Can anyone resolve my confusion?
Android Packaging are the group of libraries that you used for your particular task.
Suppose you want to use retrofit Networking library in your project, However, you need to use some callback method and those callback methods will import via package.
Here one more practical example, you want to work with Java then JAVA SDK here, you have to set in environment variable then you use methods in your framework.
Now let me come of Effection, so yes some libraries got update and some deprecate due to advancement feature. Yes, it impacts on your project. not in meantime but yes in future if there is any advance feature.

How to prevent "Call requires API level" from 3rd party libraries

App Code
When we use some code in our Android application that does not exist in the min-version SDK, Android Studio will show an error about it.
Example:
Let's assume my app has target SDK 26 and min SDK 21 and my code tries to call Objects.isNull(var);: then we get a nice error-message:
Call requires API level 24 (current min is 21): java.util.Objects#isNull
AFAIK this is a Lint message (not a compiler warning or error).
Third party code
How can we have the same checks for 3rd party java libraries?
Example:
when the project depends on a lib.jar file and this library internally uses Objects.isNull, then we don't get any error/warning and the app will crash on older devices.
One way to avoid this is to make Instrumentation Tests - but these tests are slow and you never have 100% code coverage.
e.g. I actually thought that ProGuard should report this issue. But it doesn't.
Maybe because it uses the target Android SDK min SDK?
So what can we do about this in the following 2 situations:
we must use the 3rd party library as it is
we can fork the 3rd party library and can use this fork: what could we do to find/avoid these errors: e.g. should we convert it to an aar?
How can we have the same checks for 3rd party java libraries?
Add the source code to your project.
we must use the 3rd party library as it is
Ask its developers what the relevant minSdkVersion is for the library, then set yours to match, or otherwise avoid calling their library on older devices.
we can fork the 3rd party library and can use this fork: what could we do to find/avoid these errors: e.g. should we convert it to an aar?
Add the source code to your project. Or, create some other project with the source code. Lint checks source code, not compiled code. If you create some other project with the source code, you would need to have it compile a JAR or AAR and make that available to your main project.

React native and Android 7 support with NDK restrictions

Native libraries must use only public API, and must not link against non-NDK platform libraries. Starting with API 24 this rule is enforced and applications are no longer able to load non-NDK platform libraries. The rule is enforced by the dynamic linker, so non-public libraries are not accessible regardless of the way code tries to load them: System.loadLibrary(...), DT_NEEDED entries, and direct calls to dlopen(...) will fail in exactly the same way.
https://android-developers.blogspot.com.by/2016/06/android-changes-for-ndk-developers.html
As I understand now React Native depends on native libraries,
any news about it?
That note refers only to non-public APIs. You still can load native libraries and still can use System.loadLibrary and dlopen as long as you are loading public APIs.

In Android, how to force the native code to use my version of a shared library, instead of the system's?

Android already has the PCRE shared library ("/system/lib/libpcre.so"), but it's compiled without Unicode support, so I've built my own version of PCRE for Android. My native code is linked to the PCRE shared library. However, when I run my app, it uses the system's version of PCRE, rather than the one I've built, even though my APK does include my version of PCRE. How do I make it use my version of PCRE rather than the system's? Generally in Linux I use "LD_LIBRARY_PATH" or "RPATH", but on Android I don't know how to use them, if that's at all possible.
You can load("your-path-to-lib") before you load the main library. With this API you can load a native library at arbitrary location. But the easiest way is to rely on the default behavior of build and installer, which will pack the native libraries (named libsomething.so) that it finds in libs/<ABI> folders, into the APK file, and unpack the ABI variant that matches the target into
getContext().getApplicationInfo().nativeLibraryDir
(this was added in API level 9)
If the library is pre-loaded, you cannot have your library side-by-side with the system one, due to a bug that invloved older versions of Android. Still, you may succeed to unload it manually, using dlclose():
handle = dlopen("<libname>", RTLD_NOLOAD);
dlclose(handle);
dlclose(handle); // twice, because dlopen() increments ref count
You will probably do these manipulations in a separate small dlclose_helper.so. Load this helper load before you load the main library, which needs the private version of <libname>.
A fix was introduced for API level 23 that lets us finally load both dir1/libx.so and dir2/libx.so (see the official doc).
Note that for API level 24, new restrictions have also been introduced that limits access to system libraries (you can only load white-listed ones).
I believe the only way is to rename the library (libpcre_myapp, for example).
Note that renaming just the file probably is not sufficient, but changing the SO_NAME ELF property.

Android: my application is too large and gives "Unable to execute dex: method ID not in [0, 0xffff]: 65536"?

I am trying to integrate my application with Box, Dropbox, and Google Drive. All 3 of these services require a number of 3rd party jars. Additionally, my application already requires a few 3rd party jars. Now when I try to run my application from eclipse I get the following error:
Unable to execute dex: method ID not in [0, 0xffff]: 65536 Conversion
to Dalvik format failed: Unable to execute dex: method ID not in [0,
0xffff]: 65536
It seems that this error occurs because my application has too many methods. I'm fairly certain the bulk of these methods are from the 3rd party jars, so it is unrealistic to try to solve this by simplifying my code. I found these two suggestions online.
add dex.force.jumbo=trueto project.properties (and use adt version 21). I did this but still get the error.
Use multiple dex files as explained here: http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html. This seems likely to be the only option, but I don't understand how it applies in my case. The issue is that services like Drive have too many dependencies. Wouldn't this solution require that I modify the Drive source to use inflection when referring to its dependencies? (this is clearly not an option).
Use proguard to shrink remove unused code/methods. Exporting my application with proguard does work, and the document service integration works as expected on a >4.0 device. However, classnotfound errors are thrown when testing on a 2.3 device.
So, I am hoping for some advice on this issue. Is option 2 a solution for my case? Is there another solution I should consider?
You can also develop one or more of these as a plugin to your main app, in the form of a separate APK available for download. That APK would expose some component that the main app would use -- since I do not know the nature of your integration with these services, I cannot make a more specific recommendation about that. You would use your own signature-level custom <permission> to secure communications between the two apps. And, as a bonus, if using the third-party library adds requirements for additional permissions, you would only need those permissions in the plugin APK, keeping your main APK smaller.
***NEW**** All of the other answers are now outdated. Here's the new fix
Android 5.0 and higher
Multi-dex support is included automatically. From the docs:
Android 5.0 and higher uses a runtime called ART which natively
supports loading multiple dex files from application APK files. ART
performs pre-compilation at application install time which scans for
classes(..N).dex files and compiles them into a single .oat file for
execution by the Android device. For more information on the Android
5.0 runtime, see Introducing ART.
Below Android 5.0
Simply add the Android mult-dex support tool to your gradle build:
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
The Dalvik VM can have a maximum of 65536 methods per dex file, due to the bytecode instruction set not having a way to refer to method numbers requiring more than 16 bits (as pointed out by #danfuzz in the comments).
While it is possible to fix this using multiple dex files, Facebook found another fix that they could deploy within their app to get around the problem.
See vm/LinearAlloc.c and you can find this code: (5MiB under Android 2.3.3, 8MiB after Android 4.0 as my investigation)
#define DEFAULT_MAX_LENGTH (5*1024*1024)
...
LinearAllocHdr* pHdr;
...
pHdr->mapLength = DEFAULT_MAX_LENGTH;
I suppose that the 'Facebook fix' is editing this memory by using native C pointer.
IMHO LinearAlloc problem and this method ID problem is different thing.
I faced this issue recently. After scouring the web for some more detailed implementation, I realized there wasn't much out there other than:
Good but a little outdated now that Gradle is around: http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html
Not much details but a vague idea of how it could be done: https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920
I realized that the problem was not necessarily that there were too many methods in my code, but that the full dex of my code and other libraries was the issue. So, if I could compile my code against the libraries but not include them in the classes.dex, and then dex the libraries separately, and then put it all together at runtime it should work. The only issue left to address is the class loader, which Facebook mentioned in passing.
So with a little reflection and some Groovy code, I think I came up with a relatively stable way to package the libraries and the application code into separate dex files.
https://gist.github.com/nickcaballero/7045993
Most of the problems with hitting the 65k method limit are related with the use of the mastodontic Google Play Services in your apps. Recently, you can get more granularity when using it.
Following this guide, you can use only parts that you want. Probably this will fix the problem, avoiding some black-magic tricks, or using multiDex. For example, if you only want Google Maps in your app (and you aren't using ads, wallet, google wear, analytics, etc...), using the entire dependency is a waste of time/space. You can use it that way:
compile com.google.android.gms:play-services-base:6.5.87
compile com.google.android.gms:play-services-maps:6.5.87
You can read the entire list of "parts" in this link
Here is a script I wrote for counting the number of methods in each jar (and in total) for a specific folder.
Once you count the methods you can concentrate on refactoring and removing heavy libraries.
You need to enable the Dex support for that. So you need to do these steps:
Gradle plugin v0.14.0 for Android adds support for multi-dex. To enable, you just have to declare it in build.gradle:
android {
defaultConfig {
...
multiDexEnabled = true
}
}
if app support > 5.0 (that is, if your minSdkVersion is 20 or below) you also have to dynamically patch the application ClassLoader, so it will be able to load classes from secondary dexes. for that you can add this lib.
dependencies {
...
compile 'com.android.support:multidex:1.0.0'
}
enable in code for that you have these option. choose one which suits you best
A. Add MultiDexApplication in manifest manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.multidex.App"> <application
android:name="android.support.multidex.MultiDexApplication">
</application>
</manifest>
B. Extend the application by MultiDexApplication
public class App extends MultiDexApplication { .. }
C. install it in application in attaching base context.
public class App {
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
..
}
}
For more go through this link MultiDex.

Categories

Resources