6

I have an Android app that uses some JNI code. Long story short (pun intended), it is nearly impossible to convert the JNI libraries to 64-bit as it would require a lot of changes. The code (both Java and JNI) works nicely on armeabi-v7a architecture.

The libraries are being loaded using loadLibrary. When I attempt to run my app on a Nexus 6, the app loads fine. As soon as loadLibrary is executed, the app crashes with the error described here.

The problem, as I understand it, is that when executing on Nexus 6, the app builds as arm64-8a. But the libraries are not built for arm64-8a (as the 64-bit version has issues I mentioned at start of the question).

My question is, can I force arm64-8a devices to also run armeabi-v7a code? How do I force my app apk to be armeabi-v7a so it is only 32-bit regardless of device?

Community
  • 1
  • 1
LNI
  • 2,935
  • 2
  • 21
  • 25

2 Answers2

20

Yes, arm64-v8a devices can also run armeabi-v7a code.

When the APK is installed, the installer checks if the package contains libraries in the official directories, and marks the activity as 32 or 64 bit depending on the outcome.

If it finds libraries in lib/arm64-v8a within the APK (normally taken from the directory libs/arm64-v8a in the build directory), it will be marked as 64 bit, and will ignore all other directories. If it finds libraries in lib/armeabi-v7a or lib/armeabi in the APK, the process is marked as 32 bit. If there's no native libraries in any of these, the installer assumes that the application doesn't use native code at all and is free to run it in either mode, in practice in 64 bit mode.

Now if you do ship some, but not all, libraries in 64 bit mode, the process will be launched in 64 bit mode and will be unable to load the 32 bit libraries (which won't even be installed). In this case, you must avoid bundling any 64 bit libraries unless all of them are available.

Or you don't use the official libs directory but install your libraries some other way (e.g. by downloading them at runtime or keeping them in e.g. assets), the system has no idea that your process wants to run libraries in 32 bit mode (at which point it is too late to switch to the other mode). In these cases, make sure to include at least some dummy library in the normal/official way, in order to flag the application as 32 bit.

See https://stackoverflow.com/a/33919454/3115956, https://stackoverflow.com/a/27713998/3115956 and https://stackoverflow.com/a/35450911/3115956 for answers to similar issues.

Community
  • 1
  • 1
mstorsjo
  • 12,983
  • 2
  • 39
  • 62
  • Thanks for your answer. I think there is a complexity hampering what you described in second para - I have external dependencies defined (specifically, realm and amazon AWS) and they seem to be downloading arm64-v8a. I changed my JNI library to .a file but am not sure how to have it loaded appropriately. Can I force my library to be loaded BEFORE realm etc have a chance to influence the ABI choice? The dependencies are defined in app build.gradle, e.g. `compile 'com.amazonaws:aws-android-sdk-s3:2.2.11'` – LNI May 17 '16 at 01:11
  • 1
    The actual order of the libraries being loaded doesn't matter; what matters is what different ABI directories exist in the APK. If one of your dependencies contains `arm64-v8a`, then this directory will end up in the APK, and the APK installer will pick this architecture. Try looking at your built APK (`unzip -l filename.apk`) and see what architecture directories it contains. What you can do, though, is to filter out which ABIs to actually include; try adding `abiFilters 'armeabi-v7a'` in your gradle file, to make it only include this single architecture. – mstorsjo May 17 '16 at 06:06
  • I marked your answer as correct, as I was able to verify that the app defaults to 32-bit when another 64-bit library is not present. In my case the problem is being caused by realm-android - I have entries in both the app and project build.gradle files to enable realm plugin. This was forcing arm64-v8a libraries to be loaded. I will try out the abiFilters step and amend this comment if it works. – LNI May 17 '16 at 06:23
  • Problem with abiFilters, as I understand it, is that it's applicable only to the ndk step. I already have that sorted out with defining `APP_ABI := armeabi-v7a` in Application.mk. My problem is directly related to the installation instructions at https://realm.io/docs/java/latest/#installation - the changes suggested here to build.gradle files override the NDK settings. – LNI May 17 '16 at 06:31
  • 2
    No, abiFilters is not only applicable to the step when you build your own native code, it also applies to filtering out unwanted architectures that get included implicitly via your dependencies. – mstorsjo May 17 '16 at 06:38
  • Is there any update about loading a single 32-bit library as Google play now force to use 64-bit – Mohamed Saber Aug 16 '19 at 16:47
  • As Google Play requires you to have 64 bit versions of apps, that means the whole process will run in 64 bit mode (on 64 bit capable devices), and therefore, you do need 64 bit versions of all libraries you are going to load. – mstorsjo Aug 16 '19 at 18:44
0

Very simple actually, just add this to your manifest:

android:multiArch="true" 
android:use32bitAbi="true"
Codemaker2015
  • 12,190
  • 6
  • 97
  • 81