Repository: bazelbuild/bazel
Issue: `--fat_apk_cpu` doesn't pack multi-arch libraries from aar_import targets
Labels: P1
team-Android

If an aar contains .so files for multiple architectures (e.g. foo and bar), and an android_binary depends on this aar, `--fat_apk_cpu=foo,bar` doesn't pack both so files into the final APK correctly. 

The current behavior only packs the .so for one target configuration into the APK.

Issue comments:
In preparing for the new 64 bit support requirment incoming for August 1st https://developer.android.com/distribute/best-practices/develop/64-bit

I have come across this issue as well. Is there a recommended workaround? Right now our best option seems to be to generate both versions separately, merge them and sign the resulting APK.
Hi, my team has also found this issue. Is there any plan to address this soon/before the August 1st cut off?
Bumping this up due to the hard requirement on apps depending on multi-arch splits over 32 and 64 bit native libs.
WIP fix: https://github.com/bazelbuild/bazel/pull/8510

Using https://github.com/jin/repro/tree/master/8283 as repro:

```
$ bazel-dev build --fat_apk_cpu=armeabi-v7a,x86 :app && zipinfo bazel-bin/app.apk
INFO: Analyzed target //:app (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //:app up-to-date:
  bazel-bin/app_deploy.jar
  bazel-bin/app_unsigned.apk
  bazel-bin/app.apk
INFO: Elapsed time: 0.222s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
Archive:  bazel-bin/app.apk
Zip file size: 475815 bytes, number of entries: 10
-rw----     2.0 fat        9 b- stor 10-Jan-01 00:00 nativedeps
-rw----     2.0 fat    21792 b- defN 10-Jan-01 00:00 lib/armeabi-v7a/libapp.so
-rw----     2.0 fat     6424 b- defN 10-Jan-01 00:00 lib/x86/libapp.so
-rw----     2.0 fat      920 bl defN 10-Jan-01 00:00 classes.dex
-rw-rw-rw-  2.3 unx     1168 b- defX 10-Jan-01 00:00 AndroidManifest.xml
?rw-------  2.0 unx   184888 b- stor 10-Jan-01 00:00 lib/armeabi-v7a/libenvoy_aar_jni.so
?rw-------  2.0 unx   268104 b- stor 10-Jan-01 00:00 lib/x86/libenvoy_aar_jni.so
-rw----     2.0 fat      648 b- defN 10-Jan-01 00:00 META-INF/CERT.SF
-rw----     2.0 fat     1203 b- defN 10-Jan-01 00:00 META-INF/CERT.RSA
-rw----     2.0 fat      563 b- defN 10-Jan-01 00:00 META-INF/MANIFEST.MF
```
The fix will be in 0.27.
Thanks @jin!

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index 8d85efc9cff4f5..c6d74a62fb3296 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -37,6 +37,7 @@
 import com.google.devtools.build.lib.actions.ParamFileInfo;
 import com.google.devtools.build.lib.actions.ParameterFile;
 import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
+import com.google.devtools.build.lib.analysis.AnalysisUtils;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -46,6 +47,7 @@
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.Runfiles;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
 import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
 import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
 import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg;
@@ -454,8 +456,19 @@ public static RuleConfiguredTargetBuilder createAndroidBinary(
             derivedJarFunction,
             proguardOutputMap);
 
-    NestedSet<Artifact> nativeLibsAar =
-        AndroidCommon.collectTransitiveNativeLibs(ruleContext).build();
+    // Collect all native shared libraries across split transitions. Some AARs contain shared
+    // libraries across multiple architectures, e.g. x86 and armeabi-v7a, and need to be packed
+    // into the APK.
+    NestedSetBuilder<Artifact> transitiveNativeLibs = NestedSetBuilder.naiveLinkOrder();
+    for (Map.Entry<com.google.common.base.Optional<String>,
+        ? extends List<? extends TransitiveInfoCollection>> entry :
+        ruleContext.getSplitPrerequisites("deps").entrySet()) {
+      for (AndroidNativeLibsInfo provider : AnalysisUtils.getProviders(
+          entry.getValue(), AndroidNativeLibsInfo.PROVIDER)) {
+        transitiveNativeLibs.addTransitive(provider.getNativeLibs());
+      }
+    }
+    NestedSet<Artifact> nativeLibsAar = transitiveNativeLibs.build();
 
     DexPostprocessingOutput dexPostprocessingOutput =
         androidSemantics.postprocessClassesDexZip(


Test patch:
diff --git a/src/test/shell/bazel/android/BUILD b/src/test/shell/bazel/android/BUILD
index e630e7f4cd7ca8..f3fd31364bf44e 100644
--- a/src/test/shell/bazel/android/BUILD
+++ b/src/test/shell/bazel/android/BUILD
@@ -55,6 +55,7 @@ sh_test(
     srcs = ["aar_integration_test.sh"],
     data = [
         ":android_helper",
+        "//external:android_ndk_for_testing",
         "//external:android_sdk_for_testing",
         "//src/test/shell/bazel:test-deps",
     ],
diff --git a/src/test/shell/bazel/android/aar_integration_test.sh b/src/test/shell/bazel/android/aar_integration_test.sh
index 545fff4f5f4453..06fdcd1a0ffe0f 100755
--- a/src/test/shell/bazel/android/aar_integration_test.sh
+++ b/src/test/shell/bazel/android/aar_integration_test.sh
@@ -110,4 +110,31 @@ EOF
   assert_one_of $apk_contents "res/layout/mylayout.xml"
 }
 
+function test_android_binary_fat_apk_contains_all_shared_libraries() {
+  create_new_workspace
+  setup_android_sdk_support
+  setup_android_ndk_support
+  # sample.aar contains native shared libraries for x86 and armeabi-v7a
+  cp "${TEST_SRCDIR}/io_bazel/src/test/shell/bazel/android/sample.aar" .
+  cat > AndroidManifest.xml <<EOF
+<manifest package="com.example"/>
+EOF
+  cat > BUILD <<EOF
+aar_import(
+  name = "sample",
+  aar = "sample.aar",
+)
+android_binary(
+  name = "app",
+  custom_package = "com.example",
+  manifest = "AndroidManifest.xml",
+  deps = [":sample"],
+)
+EOF
+  assert_build :app --fat_apk_cpu=x86,armeabi-v7a
+  apk_contents="$(zipinfo -1 bazel-bin/app.apk)"
+  assert_one_of $apk_contents "lib/x86/libapp.so"
+  assert_one_of $apk_contents "lib/armeabi-v7a/libapp.so"
+}
+
 run_suite "aar_import integration tests"