Skip to content

Commit

Permalink
Re-implement native library search and copies.
Browse files Browse the repository at this point in the history
We now use a two step approach :

- First we look through the list of shared libraries in an
  APK, and choose an ABI based on the (priority)  list of ABIs
  a given device supports.
- Then we look through the list of shared libraries and copy
  all shared libraries that match the ABI we've selected.

This fixes a long-standing bug where we would sometimes copy
a mixture of different ABIs to the device, and also allows us
to clearly pick an ABI to run an app with.

The code in NativeLibraryHelper has been refactored so that all
file name validation & matching logic is done in a single place
(NativeLibrariesIterator). This allows us to avoid a lot of
redundant logic and straightens out a few corner cases (for eg.
where the abi determination & copying logic do not agree on
what files to skip).

bug: https://code.google.com/p/android/issues/detail?id=65053
bug: 13647418

Change-Id: I34d08353f24115b0f6b800a7eda3ac427fa25fef
Co-Authored-By: Zhenghua Wang <[email protected]>
Co-Authored-By: Ramin Zaghi <[email protected]>
Co-Authored-By: Narayan Kamath <[email protected]>
  • Loading branch information
3 people committed Apr 9, 2014
1 parent a6f5e79 commit 1378aba
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 112 deletions.
19 changes: 19 additions & 0 deletions core/java/android/content/pm/PackageManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,25 @@ public NameNotFoundException(String name) {
*/
public static final int INSTALL_FAILED_USER_RESTRICTED = -111;

/**
* Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the system failed to install the package because its packaged native code did not
* match any of the ABIs supported by the system.
*
* @hide
*/
public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -112;

/**
* Internal return code for NativeLibraryHelper methods to indicate that the package
* being processed did not contain any native code. This is placed here only so that
* it can belong to the same value space as the other install failure codes.
*
* @hide
*/
public static final int NO_NATIVE_LIBRARIES = -113;

/**
* Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
* package's data directory.
Expand Down
9 changes: 8 additions & 1 deletion core/java/android/os/Build.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ public class Build {

/** A hardware serial number, if available. Alphanumeric only, case-insensitive. */
public static final String SERIAL = getString("ro.serialno");


/**
* A list of ABIs (in priority) order supported by this device.
*
* @hide
*/
public static final String[] SUPPORTED_ABIS = getString("ro.product.cpu.abilist").split(",");

/** Various version strings. */
public static class VERSION {
/**
Expand Down
70 changes: 54 additions & 16 deletions core/java/com/android/internal/content/NativeLibraryHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.android.internal.content;

import android.os.Build;
import android.content.pm.PackageManager;
import android.util.Slog;

import java.io.File;
Expand All @@ -31,38 +31,76 @@ public class NativeLibraryHelper {

private static final boolean DEBUG_NATIVE = false;

private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2);
/**
* A handle to an opened APK. Used as input to the various NativeLibraryHelper
* methods. Allows us to scan and parse the APK exactly once instead of doing
* it multiple times.
*
* @hide
*/
public static class ApkHandle {
final String apkPath;
final long apkHandle;

public ApkHandle(String path) {
apkPath = path;
apkHandle = nativeOpenApk(apkPath);
}

public ApkHandle(File apkFile) {
apkPath = apkFile.getPath();
apkHandle = nativeOpenApk(apkPath);
}

public void close() {
nativeClose(apkHandle);
}
}


private static native long nativeOpenApk(String path);
private static native void nativeClose(long handle);

private static native long nativeSumNativeBinaries(long handle, String cpuAbi);

/**
* Sums the size of native binaries in an APK.
* Sums the size of native binaries in an APK for a given ABI.
*
* @param apkFile APK file to scan for native libraries
* @return size of all native binary files in bytes
*/
public static long sumNativeBinariesLI(File apkFile) {
final String cpuAbi = Build.CPU_ABI;
final String cpuAbi2 = Build.CPU_ABI2;
return nativeSumNativeBinaries(apkFile.getPath(), cpuAbi, cpuAbi2);
public static long sumNativeBinariesLI(ApkHandle handle, String abi) {
return nativeSumNativeBinaries(handle.apkHandle, abi);
}

private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath,
String cpuAbi, String cpuAbi2);
private native static int nativeCopyNativeBinaries(long handle,
String sharedLibraryPath, String abiToCopy);

/**
* Copies native binaries to a shared library directory.
*
* @param apkFile APK file to scan for native libraries
* @param handle APK file to scan for native libraries
* @param sharedLibraryDir directory for libraries to be copied to
* @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
* error code from that class if not
*/
public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) {
final String cpuAbi = Build.CPU_ABI;
final String cpuAbi2 = Build.CPU_ABI2;
return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi,
cpuAbi2);
public static int copyNativeBinariesIfNeededLI(ApkHandle handle, File sharedLibraryDir,
String abi) {
return nativeCopyNativeBinaries(handle.apkHandle, sharedLibraryDir.getPath(), abi);
}

/**
* Checks if a given APK contains native code for any of the provided
* {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching
* ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the
* APK doesn't contain any native code, and
* {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match.
*/
public static int findSupportedAbi(ApkHandle handle, String[] supportedAbis) {
return nativeFindSupportedAbi(handle.apkHandle, supportedAbis);
}

private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);

// Convenience method to call removeNativeBinariesFromDirLI(File)
public static boolean removeNativeBinariesLI(String nativeLibraryPath) {
return removeNativeBinariesFromDirLI(new File(nativeLibraryPath));
Expand Down
Loading

0 comments on commit 1378aba

Please sign in to comment.