Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile install fails to load native libraries provided by AARs #13661

Closed
Bencodes opened this issue Jul 9, 2021 · 1 comment · May be fixed by #15361
Closed

Mobile install fails to load native libraries provided by AARs #13661

Bencodes opened this issue Jul 9, 2021 · 1 comment · May be fixed by #15361
Labels

Comments

@Bencodes
Copy link
Contributor

Bencodes commented Jul 9, 2021

Description of the problem / feature request:

Mobile install fails to load native libraries embedded in the incremental APK while using mobile-install.

Bugs: what's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.

Use mobile-install to build and install an Android app that includes an AARs containing native libraries. The application will crash at runtime when you load the library using System#loadLibrary.

// DemoApplication.java

package cm.ben.android.bazel.bug;

import android.app.Application;

public class DemoApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        System.loadLibrary("bugsnag-ndk");
    }
}
#### BUILD

load("@build_bazel_rules_android//android:rules.bzl", "android_binary")

android_binary(
    name = "app",
    custom_package = "cm.ben.android.bazel.bug",
    manifest = "AndroidManifest.xml",
    srcs = ["DemoApplication.java"],
    deps = [
        "@maven//:com_bugsnag_bugsnag_android",
        "@maven//:com_bugsnag_bugsnag_android_core",
        "@maven//:com_bugsnag_bugsnag_plugin_android_anr",
        "@maven//:com_bugsnag_bugsnag_plugin_android_ndk",
    ],
)


#### WORKSPACE

workspace(name = "bazel_mobile_install_bug")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

## JVM External

_RULES_JVM_EXTERNAL_VERSION = "4.1"
_RULES_JVM_EXTERNAL_SHA = "f36441aa876c4f6427bfb2d1f2d723b48e9d930b62662bf723ddfb8fc80f0140"

http_archive(
    name = "rules_jvm_external",
    sha256 = _RULES_JVM_EXTERNAL_SHA,
    strip_prefix = "rules_jvm_external-{}".format(_RULES_JVM_EXTERNAL_VERSION),
    urls = [
        "https://github.com/bazelbuild/rules_jvm_external/archive/{}.zip".format(_RULES_JVM_EXTERNAL_VERSION),
    ],
)

load("@rules_jvm_external//:defs.bzl", "maven_install")

maven_install(
    artifacts = [
        "com.bugsnag:bugsnag-android:4.22.2",
        "com.bugsnag:bugsnag-android-core:4.22.2",
        "com.bugsnag:bugsnag-plugin-android-anr:4.22.2",
        "com.bugsnag:bugsnag-plugin-android-ndk:4.22.2",
    ],
    repositories = [
        "https://maven.google.com",
        "https://repo1.maven.org/maven2",
    ],
)

## Android

_RULES_ANDROID_VERSION = "0.1.1"
_RULES_ANDROID_SHA = "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806"

http_archive(
    name = "build_bazel_rules_android",
    sha256 = _RULES_ANDROID_SHA,
    strip_prefix = "rules_android-{}".format(_RULES_ANDROID_VERSION),
    urls = [
        "https://github.com/bazelbuild/rules_android/archive/v{}.zip".format(_RULES_ANDROID_VERSION),
    ],
)

load("@build_bazel_rules_android//android:rules.bzl", "android_sdk_repository", "android_ndk_repository")

android_sdk_repository(
    name = "androidsdk",
    api_level = 29,
    build_tools_version = "29.0.3",
)

android_ndk_repository(
    name = "androidndk",
    api_level = 29,
)

What operating system are you running Bazel on?

MacOs Catalina 10.15.7

What's the output of bazel info release?

release 4.1.0

Have you found anything relevant by searching the web?

The incremental class loader being injected into the application via StubApplication doesn't fall back to the APK when BaseDexClassLoader#findLibrary is called. Iterating over and calling BaseDexClassLoader#findLibrary on the parent class loaders in DelegateClassLoader does work around the problem:

  private static class DelegateClassLoader extends BaseDexClassLoader {

    // ...

    @Override
    public String findLibrary(String name) {
      String foundLib = super.findLibrary(name);

      for (ClassLoader parent = getParent(); foundLib == null && parent != null; parent = parent.getParent()) {
        if (parent instanceof BaseDexClassLoader) {
          foundLib = ((BaseDexClassLoader)parent).findLibrary(name);
        }
      }
      return foundLib;
    }
}

Any other information, logs, or outputs that you want to share?

The incremental APK does have the native libraries in it

zipinfo -1 bazel-bin/app_incremental.apk | grep "bugsnag-ndk"
lib/arm64-v8a/libbugsnag-ndk.so
lib/armeabi-v7a/libbugsnag-ndk.so
lib/x86/libbugsnag-ndk.so
lib/x86_64/libbugsnag-ndk.so

Using build instead of mobile-install works as expected:

bazel build //:app
adb install -r bazel-bin/app.apk

The runtime Stacktrace from trying to load a native library

2021-07-09 09:46:26.999 24078-24078/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: cm.ben.android.bazel.bug, PID: 24078
    java.lang.UnsatisfiedLinkError: com.google.devtools.build.android.incrementaldeployment.IncrementalClassLoader$DelegateClassLoader[DexPathList[[dex file "/data/local/tmp/incrementaldeployment/cm.ben.android.bazel.bug/dex/incremental_classes1.dex"],nativeLibraryDirectories=[/data/user/0/cm.ben.android.bazel.bug/lib, /system/lib64, /system_ext/lib64]]] couldn't find "libbugsnag-ndk.so"
        at java.lang.Runtime.loadLibrary0(Runtime.java:1083)
        at java.lang.Runtime.loadLibrary0(Runtime.java:1008)
        at java.lang.System.loadLibrary(System.java:1664)
        at cm.ben.android.bazel.bug.DemoApplication.onCreate(DemoApplication.java:10)
        at com.google.devtools.build.android.incrementaldeployment.StubApplication.onCreate(StubApplication.java:572)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1192)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6719)
        at android.app.ActivityThread.access$1300(ActivityThread.java:237)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1913)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7664)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
@Bencodes
Copy link
Contributor Author

Bencodes commented Jul 9, 2021

Should the mobile-install actually be sending the native libraries in the AAR to the device using --native_lib instead of bundling them up inside the incremental APK? https://github.com/Bencodes/bazel/blob/master/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java#L422

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants