androidgradleandroid-gradle-plugin

How to fix Android project build failing with .so is not an ABI


I have a project that was using Android Gradle Plugin 7.4.2, I used the upgrade assistant to update to 8.0.2 but now my project doesn't build with the following error:

Cause: jni extracted from path /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so is not an ABI

Does anyone know if there is some way to specify in Gradle not to use the arm64-v8.2-a ABI versions of this library? I tried adding the following:

    ndk {
        // Specifies the ABI configurations of your native
        // libraries Gradle should build and package with your app.
        abiFilters 'arm64-v8a'
    }

and also

splits {
        abi {
            enable true
            reset()
            include "arm64-v8a"
        }
    }

but those didn't help. If I revert the upgrade the project builds fine, but I want to use the latest version of Gradle plugin.

Edit: For extra information, this dependency is coming in the form of a .AAR file and included within it is arm64-v8a and arm64-v8.2-a versions of the compiled native .so file. It looks like in older Android Gradle Plugin versions the v8.2 is just ignored but now it is getting automatically picked up and causing this issue?


Solution

  • The code triggering the error resides in MergeNativeLibsTask.kt:

        /**
         * [file] is one of these two kinds:
         *    (1) /path/to/{x86/lib.so}
         *    (2) /path/to/x86/{lib.so}
         * Where the value in {braces} is the [relativePath] from the file visitor.
         * The first (1) is from tasks that process all ABIs in a single task.
         * The second (2) is from tasks the where each task processes one ABI.
         *
         * This function distinguishes the two cases and returns a relative path that always
         * starts with an ABI. So, for example, both of the cases above would return:
         *
         *    x86/lib.so
         *
         */
        private fun toAbiRootedPath(file : File, relativePath: RelativePath) : String {
            return if (abiTags.any { it == relativePath.segments[0] }) {
                // Case (1) the relative path starts with an ABI name. Return it directly.
                relativePath.pathString
            } else {
                // Case (2) the relative path does not start with an ABI name. Prepend the
                // ABI name from the end of [file] after [relativePath] has been removed.
                var root = file
                repeat(relativePath.segments.size) { root = root.parentFile }
                val abi = root.name
                if (!abiTags.any { it == abi }) {
                    error("$abi extracted from path $file is not an ABI")
                }
                abi + separatorChar + relativePath.pathString
            }
        }
    

    Based on the fact that your error starts with "jni", it appears that in your case, it picks the "jni" part of the path as the extracted ABI.

    The code really looks like it requires a supported ABI name to be either the first segment of the relative path, or the name of the directory just outside of the relative path.

    In your case, I surmise that you have a file value of /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so and a relativePath arm64-v8.2-a/libarmnn_delegate_jni.so.

    I don't see any way to make this function pass except to make sure it is not called at all for this file. If that's possible, I don't know how (but I'm certainly no expert in the area). The other option is to remove the "bad" ABI from the dependency (if you have control over it) -- the list of accepted ones should be here.

    This has previously been reported as a bug on the Google Issue Tracker, but there doesn't appear to be much (public) progress. Please do not post in those comments if you don't have anything new to add; mark the issue with the star icon or "+1" button instead.