Multi-arch application installs.
Each application now has two ABIs, the primary
and the secondary. The app is always launched with
the primary, but the secondary might be used by other apps
that load the given applications code. This implies we
must:
- dex2oat the app both ways.
- extract shared libraries for both abis.
The former is relatively straightforward but the latter
requires us to change the layout for shared libs that we
unpack from applications. The bulk of this change deals
with the latter.
This change continues to fill in nativeLibraryPath during
scans for backwards compatibility. This will be removed in
a future patch.
Change-Id: Ia943dd11ef815c5cbfc60f17929eaa2a652a385a
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 1e93d92..4939fb6 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -491,13 +491,55 @@
public String nativeLibraryDir;
/**
- * The ABI that this application requires, This is inferred from the ABIs
+ * The path under the apps data directory we store unpacked libraries. For
+ * new installs, we create subdirectories under legacyNativeLibraryDir that are
+ * architecture specific. For legacy installs, the shared libraries are
+ * placed directly under this path.
+ *
+ * For "legacy" installs {@code nativeLibraryDir} will be equal to this path.
+ * For newer installs, it will be derived based on the codePath and the primary
+ * cpu abi.
+ *
+ * @hide.
+ */
+ public String legacyNativeLibraryDir;
+
+ /**
+ * The primary ABI that this application requires, This is inferred from the ABIs
* of the native JNI libraries the application bundles. Will be {@code null}
* if this application does not require any particular ABI.
*
+ * If non-null, the application will always be launched with this ABI.
+ *
* {@hide}
*/
- public String cpuAbi;
+ public String primaryCpuAbi;
+
+ /**
+ * The secondary ABI for this application. Might be non-null for multi-arch
+ * installs. The application itself never uses this ABI, but other applications that
+ * use its code might.
+ *
+ * {@hide}
+ */
+ public String secondaryCpuAbi;
+
+ /**
+ * The derived APK "root" for the given package. Will be non-null for bundled and
+ * updated system apps. This will be a top level path under which apks and libraries
+ * are installed, for eg. {@code /system}, {@code /oem} or {@code /vendor}. This is
+ * used to calculate the location of native code for a given package, for e.g
+ * {@code /vendor/lib} or {@code /vendor/lib64}.
+ *
+ * For app updates or fresh app installs, this will be {@code null} and we will use
+ * {@code legacyNativeLibraryDir}
+ *
+ * NOTE: This can be removed if we have a unified layout for bundled and installed
+ * apps.
+ *
+ * {@hide}
+ */
+ public String apkRoot;
/**
* The kernel user-ID that has been assigned to this application;
@@ -641,7 +683,10 @@
splitSourceDirs = orig.splitSourceDirs;
splitPublicSourceDirs = orig.splitPublicSourceDirs;
nativeLibraryDir = orig.nativeLibraryDir;
- cpuAbi = orig.cpuAbi;
+ legacyNativeLibraryDir = orig.legacyNativeLibraryDir;
+ primaryCpuAbi = orig.primaryCpuAbi;
+ secondaryCpuAbi = orig.secondaryCpuAbi;
+ apkRoot = orig.apkRoot;
resourceDirs = orig.resourceDirs;
seinfo = orig.seinfo;
sharedLibraryFiles = orig.sharedLibraryFiles;
@@ -685,7 +730,10 @@
dest.writeStringArray(splitSourceDirs);
dest.writeStringArray(splitPublicSourceDirs);
dest.writeString(nativeLibraryDir);
- dest.writeString(cpuAbi);
+ dest.writeString(legacyNativeLibraryDir);
+ dest.writeString(primaryCpuAbi);
+ dest.writeString(secondaryCpuAbi);
+ dest.writeString(apkRoot);
dest.writeStringArray(resourceDirs);
dest.writeString(seinfo);
dest.writeStringArray(sharedLibraryFiles);
@@ -728,7 +776,10 @@
splitSourceDirs = source.readStringArray();
splitPublicSourceDirs = source.readStringArray();
nativeLibraryDir = source.readString();
- cpuAbi = source.readString();
+ legacyNativeLibraryDir = source.readString();
+ primaryCpuAbi = source.readString();
+ secondaryCpuAbi = source.readString();
+ apkRoot = source.readString();
resourceDirs = source.readStringArray();
seinfo = source.readString();
sharedLibraryFiles = source.readStringArray();
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index a1566da..50a0483 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -37,6 +37,13 @@
public int versionCode;
/**
+ * The android:multiArch flag from the package manifest. If set,
+ * we will extract all native libraries for the given app, not just those
+ * from the preferred ABI.
+ */
+ public boolean multiArch;
+
+ /**
* Specifies the recommended install location. Can be one of
* {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage
* {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ab0bf25..6e0ca50 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -249,6 +249,8 @@
/** Paths of any split APKs, ordered by parsed splitName */
public final String[] splitCodePaths;
+ public final boolean multiArch;
+
private PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
String[] splitCodePaths) {
this.packageName = baseApk.packageName;
@@ -259,6 +261,7 @@
this.codePath = codePath;
this.baseCodePath = baseApk.codePath;
this.splitCodePaths = splitCodePaths;
+ this.multiArch = baseApk.multiArch;
}
public List<String> getAllCodePaths() {
@@ -282,9 +285,11 @@
public final int installLocation;
public final VerifierInfo[] verifiers;
public final Signature[] signatures;
+ public final boolean multiArch;
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
- int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) {
+ int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
+ boolean multiArch) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -292,6 +297,7 @@
this.installLocation = installLocation;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
this.signatures = signatures;
+ this.multiArch = multiArch;
}
}
@@ -1114,6 +1120,7 @@
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
int numFound = 0;
+ boolean multiArch = false;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
String attr = attrs.getAttributeName(i);
if (attr.equals("installLocation")) {
@@ -1123,8 +1130,11 @@
} else if (attr.equals("versionCode")) {
versionCode = attrs.getAttributeIntValue(i, 0);
numFound++;
+ } else if (attr.equals("multiArch")) {
+ multiArch = attrs.getAttributeBooleanValue(i, false);
+ numFound++;
}
- if (numFound >= 2) {
+ if (numFound >= 3) {
break;
}
}
@@ -1149,7 +1159,7 @@
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
- installLocation, verifiers, signatures);
+ installLocation, verifiers, signatures, multiArch);
}
/**
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index d66a7bb..d76d0d4 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -131,10 +131,15 @@
*
* @return size of all native binary files in bytes
*/
- public static long sumNativeBinariesLI(Handle handle, String abi) {
+ public static long sumNativeBinariesLI(Handle handle, String[] abis) {
long sum = 0;
for (long apkHandle : handle.apkHandles) {
- sum += nativeSumNativeBinaries(apkHandle, abi);
+ // NOTE: For a given APK handle, we parse the central directory precisely
+ // once, but prefix matching of entries requires a CD traversal, which can
+ // take a while (even if it needs no additional I/O).
+ for (String abi : abis) {
+ sum += nativeSumNativeBinaries(apkHandle, abi);
+ }
}
return sum;
}
@@ -196,45 +201,47 @@
private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
// Convenience method to call removeNativeBinariesFromDirLI(File)
- public static boolean removeNativeBinariesLI(String nativeLibraryPath) {
- if (nativeLibraryPath == null) return false;
- return removeNativeBinariesFromDirLI(new File(nativeLibraryPath));
+ public static void removeNativeBinariesLI(String nativeLibraryPath) {
+ if (nativeLibraryPath == null) return;
+ removeNativeBinariesFromDirLI(new File(nativeLibraryPath), false /* delete root dir */);
}
- // Remove the native binaries of a given package. This simply
- // gets rid of the files in the 'lib' sub-directory.
- public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) {
+ /**
+ * Remove the native binaries of a given package. This deletes the files
+ */
+ public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) {
if (DEBUG_NATIVE) {
- Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryDir.getPath());
+ Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath());
}
- boolean deletedFiles = false;
-
/*
* Just remove any file in the directory. Since the directory is owned
* by the 'system' UID, the application is not supposed to have written
* anything there.
*/
- if (nativeLibraryDir.exists()) {
- final File[] binaries = nativeLibraryDir.listFiles();
- if (binaries != null) {
- for (int nn = 0; nn < binaries.length; nn++) {
+ if (nativeLibraryRoot.exists()) {
+ final File[] files = nativeLibraryRoot.listFiles();
+ if (files != null) {
+ for (int nn = 0; nn < files.length; nn++) {
if (DEBUG_NATIVE) {
- Slog.d(TAG, " Deleting " + binaries[nn].getName());
+ Slog.d(TAG, " Deleting " + files[nn].getName());
}
- if (!binaries[nn].delete()) {
- Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath());
- } else {
- deletedFiles = true;
+ if (files[nn].isDirectory()) {
+ removeNativeBinariesFromDirLI(files[nn], true /* delete root dir */);
+ } else if (!files[nn].delete()) {
+ Slog.w(TAG, "Could not delete native binary: " + files[nn].getPath());
}
}
}
- // Do not delete 'lib' directory itself, or this will prevent
- // installation of future updates.
+ // Do not delete 'lib' directory itself, unless we're specifically
+ // asked to or this will prevent installation of future updates.
+ if (deleteRootDir) {
+ if (!nativeLibraryRoot.delete()) {
+ Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath());
+ }
+ }
}
-
- return deletedFiles;
}
// We don't care about the other return values for now.
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 67ed97c..20a621bd 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -50,6 +50,7 @@
import com.android.internal.os.IParcelFileDescriptorFactory;
import com.android.internal.util.ArrayUtils;
+import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -186,6 +187,7 @@
ret.verifiers = pkg.verifiers;
ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold,
abiOverride);
+ ret.multiArch = pkg.multiArch;
return ret;
}
@@ -363,31 +365,26 @@
final String resFileName = "pkg.apk";
final String publicResFileName = "res.zip";
- // The .apk file
- String codePath = pkg.baseCodePath;
- File codeFile = new File(codePath);
-
- String[] abiList = Build.SUPPORTED_ABIS;
- if (abiOverride != null) {
- abiList = new String[] { abiOverride };
- } else {
- try {
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
- NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
- abiList = Build.SUPPORTED_32_BIT_ABIS;
- }
- } catch (IOException ioe) {
- Slog.w(TAG, "Problem determining ABI for: " + codeFile.getPath());
- return null;
- }
+ if (pkg.multiArch) {
+ // TODO: Support multiArch installs on ASEC.
+ throw new IllegalArgumentException("multiArch not supported on ASEC installs.");
}
- final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+ // The .apk file
+ final String codePath = pkg.baseCodePath;
+ final File codeFile = new File(codePath);
+ final String[] abis;
+ try {
+ abis = calculateAbiList(handle, abiOverride, pkg.multiArch);
+ } catch (IOException ioe) {
+ Slog.w(TAG, "Problem determining app ABIS: " + ioe);
+ return null;
+ }
// Calculate size of container needed to hold base APK.
final int sizeMb;
try {
- sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abiIndex);
+ sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abis);
} catch (IOException e) {
Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath());
return null;
@@ -451,17 +448,18 @@
final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
if (sharedLibraryDir.mkdir()) {
int ret = PackageManager.INSTALL_SUCCEEDED;
- if (abiIndex >= 0) {
+ if (abis != null) {
+ // TODO(multiArch): Support multi-arch installs on asecs. Note that we are NOT
+ // using an ISA specific subdir here for now.
+ final String abi = abis[0];
ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
- sharedLibraryDir, abiList[abiIndex]);
- } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) {
- ret = abiIndex;
- }
+ sharedLibraryDir, abi);
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath());
- PackageHelper.destroySdDir(newCid);
- return null;
+ if (ret != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath());
+ PackageHelper.destroySdDir(newCid);
+ return null;
+ }
}
} else {
Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath());
@@ -687,14 +685,53 @@
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(pkg);
- final int abi = NativeLibraryHelper.findSupportedAbi(handle,
- (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS);
- return calculateContainerSize(pkg, handle, isForwardLocked, abi);
+ return calculateContainerSize(pkg, handle, isForwardLocked,
+ calculateAbiList(handle, abiOverride, pkg.multiArch));
} finally {
IoUtils.closeQuietly(handle);
}
}
+ private String[] calculateAbiList(NativeLibraryHelper.Handle handle, String abiOverride,
+ boolean isMultiArch) throws IOException {
+ if (isMultiArch) {
+ final int abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
+ final int abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
+
+ if (abi32 >= 0 && abi64 >= 0) {
+ return new String[] { Build.SUPPORTED_64_BIT_ABIS[abi64], Build.SUPPORTED_32_BIT_ABIS[abi32] };
+ } else if (abi64 >= 0) {
+ return new String[] { Build.SUPPORTED_64_BIT_ABIS[abi64] };
+ } else if (abi32 >= 0) {
+ return new String[] { Build.SUPPORTED_32_BIT_ABIS[abi32] };
+ }
+
+ if (abi64 != PackageManager.NO_NATIVE_LIBRARIES || abi32 != PackageManager.NO_NATIVE_LIBRARIES) {
+ throw new IOException("Error determining ABI list: errorCode=[" + abi32 + "," + abi64 + "]");
+ }
+
+ } else {
+ String[] abiList = Build.SUPPORTED_ABIS;
+ if (abiOverride != null) {
+ abiList = new String[] { abiOverride };
+ } else if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
+ NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
+ }
+
+ final int abi = NativeLibraryHelper.findSupportedAbi(handle,abiList);
+ if (abi >= 0) {
+ return new String[]{Build.SUPPORTED_ABIS[abi]};
+ }
+
+ if (abi != PackageManager.NO_NATIVE_LIBRARIES) {
+ throw new IOException("Error determining ABI list: errorCode=" + abi);
+ }
+ }
+
+ return null;
+ }
+
/**
* Calculate the container size for a package.
*
@@ -702,7 +739,7 @@
* @throws IOException when there is a problem reading the file
*/
private int calculateContainerSize(PackageLite pkg, NativeLibraryHelper.Handle handle,
- boolean isForwardLocked, int abiIndex) throws IOException {
+ boolean isForwardLocked, String[] abis) throws IOException {
// Calculate size of container needed to hold APKs.
long sizeBytes = 0;
for (String codePath : pkg.getAllCodePaths()) {
@@ -715,9 +752,8 @@
// Check all the native files that need to be copied and add that to the
// container size.
- if (abiIndex >= 0) {
- sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle,
- Build.SUPPORTED_ABIS[abiIndex]);
+ if (abis != null) {
+ sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, abis);
}
int sizeMb = (int) (sizeBytes >> 20);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 053fb5a..c7eabe8 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2985,7 +2985,7 @@
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
- String requiredAbi = (abiOverride != null) ? abiOverride : app.info.cpuAbi;
+ String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 6ad2e60..1193968 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -365,7 +365,7 @@
}
public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
- String fwdLockApkPath, String asecPath, String instructionSet, PackageStats pStats) {
+ String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
@@ -374,13 +374,17 @@
builder.append(' ');
builder.append(apkPath);
builder.append(' ');
+ // TODO: Extend getSizeInfo to look at the full subdirectory tree,
+ // not just the first level.
builder.append(libDirPath != null ? libDirPath : "!");
builder.append(' ');
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
builder.append(' ');
builder.append(asecPath != null ? asecPath : "!");
builder.append(' ');
- builder.append(instructionSet);
+ // TODO: Extend getSizeInfo to look at *all* instrution sets, not
+ // just the primary.
+ builder.append(instructionSets[0]);
String s = transaction(builder.toString());
String res[] = s.split(" ");
@@ -404,18 +408,17 @@
}
/**
- * Links the native library directory in an application's directory to its
- * real location.
+ * Links the 32 bit native library directory in an application's data directory to the
+ * real location for backward compatibility. Note that no such symlink is created for
+ * 64 bit shared libraries.
*
- * @param dataPath data directory where the application is
- * @param nativeLibPath target native library path
* @return -1 on error
*/
- public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) {
+ public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
if (dataPath == null) {
Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
return -1;
- } else if (nativeLibPath == null) {
+ } else if (nativeLibPath32 == null) {
Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
return -1;
}
@@ -423,7 +426,7 @@
StringBuilder builder = new StringBuilder("linklib ");
builder.append(dataPath);
builder.append(' ');
- builder.append(nativeLibPath);
+ builder.append(nativeLibPath32);
builder.append(' ');
builder.append(userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fe9ce8f..5c05f45 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,7 +18,6 @@
import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
-import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -34,7 +33,6 @@
import static android.system.OsConstants.EEXIST;
import static android.system.OsConstants.O_EXCL;
import static android.system.OsConstants.O_RDWR;
-import static android.system.OsConstants.O_WRONLY;
import static android.system.OsConstants.S_IRGRP;
import static android.system.OsConstants.S_IROTH;
import static android.system.OsConstants.S_IRWXU;
@@ -57,7 +55,6 @@
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
import com.android.server.LocalServices;
@@ -67,14 +64,11 @@
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.storage.DeviceStorageMonitorInternal;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
-import android.app.PackageInstallObserver;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
import android.content.BroadcastReceiver;
@@ -149,7 +143,6 @@
import android.security.SystemKeyStore;
import android.system.ErrnoException;
import android.system.Os;
-import android.system.OsConstants;
import android.system.StructStat;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -162,7 +155,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.Xml;
import android.view.Display;
import java.io.BufferedInputStream;
@@ -172,7 +164,6 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
@@ -204,7 +195,6 @@
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
/**
* Keep track of all those .apks everywhere.
@@ -233,6 +223,7 @@
private static final boolean DEBUG_APP_DIR_OBSERVER = false;
private static final boolean DEBUG_VERIFY = false;
private static final boolean DEBUG_DEXOPT = false;
+ private static final boolean DEBUG_ABI_SELECTION = false;
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
@@ -368,10 +359,10 @@
final File mAppInstallDir;
/**
- * Directory to which applications installed internally have native
- * libraries copied.
+ * Directory to which applications installed internally have their
+ * 32 bit native libraries copied.
*/
- private File mAppLibInstallDir;
+ private File mAppLib32InstallDir;
// Directory containing the private parts (e.g. code and non-resource assets) of forward-locked
// apps.
@@ -1354,7 +1345,7 @@
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
- mAppLibInstallDir = new File(dataDir, "app-lib");
+ mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
@@ -2089,7 +2080,8 @@
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
pkg.applicationInfo.dataDir =
getDataPathForPackage(packageName, 0).getPath();
- pkg.applicationInfo.cpuAbi = ps.cpuAbiString;
+ pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
+ pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
}
return generatePackageInfo(pkg, flags, userId);
}
@@ -4269,8 +4261,8 @@
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString,
- getAppInstructionSetFromSettings(ps));
+ ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
+ getAppDexInstructionSets(ps), isMultiArch(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
@@ -4334,8 +4326,8 @@
+ ps.codePathString + ": new version " + pkg.mVersionCode
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString,
- getAppInstructionSetFromSettings(ps));
+ ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
+ getAppDexInstructionSets(ps), isMultiArch(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
@@ -4585,7 +4577,7 @@
mPackageUsage.write(true);
}
- private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet,
+ private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
boolean forceDex, boolean defer, HashSet<String> done) {
for (int i=0; i<libs.size(); i++) {
PackageParser.Package libPkg;
@@ -4600,7 +4592,7 @@
}
}
if (libPkg != null && !done.contains(libName)) {
- performDexOptLI(libPkg, instructionSet, forceDex, defer, done);
+ performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
}
}
}
@@ -4610,89 +4602,98 @@
static final int DEX_OPT_DEFERRED = 2;
static final int DEX_OPT_FAILED = -1;
- private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride,
+ private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
boolean forceDex, boolean defer, HashSet<String> done) {
- final String instructionSet = instructionSetOverride != null ?
- instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
+ final String[] instructionSets = targetInstructionSets != null ?
+ targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
if (done != null) {
done.add(pkg.packageName);
if (pkg.usesLibraries != null) {
- performDexOptLibsLI(pkg.usesLibraries, instructionSet, forceDex, defer, done);
+ performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
}
if (pkg.usesOptionalLibraries != null) {
- performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSet, forceDex, defer, done);
+ performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, done);
}
}
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
final Collection<String> paths = pkg.getAllCodePaths();
for (String path : paths) {
- try {
- boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
- pkg.packageName, instructionSet, defer);
- // There are three basic cases here:
- // 1.) we need to dexopt, either because we are forced or it is needed
- // 2.) we are defering a needed dexopt
- // 3.) we are skipping an unneeded dexopt
- if (forceDex || (!defer && isDexOptNeededInternal)) {
- Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, instructionSet);
- // Note that we ran dexopt, since rerunning will
- // probably just result in an error again.
+ for (String instructionSet : instructionSets) {
+ try {
+ boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
+ pkg.packageName, instructionSet, defer);
+ // There are three basic cases here:
+ // 1.) we need to dexopt, either because we are forced or it is needed
+ // 2.) we are defering a needed dexopt
+ // 3.) we are skipping an unneeded dexopt
+ if (forceDex || (!defer && isDexOptNeededInternal)) {
+ Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
+ pkg.packageName, instructionSet);
+ // Note that we ran dexopt, since rerunning will
+ // probably just result in an error again.
+ pkg.mDexOptNeeded = false;
+ if (ret < 0) {
+ return DEX_OPT_FAILED;
+ }
+ return DEX_OPT_PERFORMED;
+ }
+ if (defer && isDexOptNeededInternal) {
+ if (mDeferredDexOpt == null) {
+ mDeferredDexOpt = new HashSet<PackageParser.Package>();
+ }
+ mDeferredDexOpt.add(pkg);
+ return DEX_OPT_DEFERRED;
+ }
pkg.mDexOptNeeded = false;
- if (ret < 0) {
- return DEX_OPT_FAILED;
- }
- return DEX_OPT_PERFORMED;
+ return DEX_OPT_SKIPPED;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Apk not found for dexopt: " + path);
+ return DEX_OPT_FAILED;
+ } catch (IOException e) {
+ Slog.w(TAG, "IOException reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (StaleDexCacheError e) {
+ Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception when doing dexopt : ", e);
+ return DEX_OPT_FAILED;
}
- if (defer && isDexOptNeededInternal) {
- if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new HashSet<PackageParser.Package>();
- }
- mDeferredDexOpt.add(pkg);
- return DEX_OPT_DEFERRED;
- }
- pkg.mDexOptNeeded = false;
- return DEX_OPT_SKIPPED;
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Apk not found for dexopt: " + path);
- return DEX_OPT_FAILED;
- } catch (IOException e) {
- Slog.w(TAG, "IOException reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (StaleDexCacheError e) {
- Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (Exception e) {
- Slog.w(TAG, "Exception when doing dexopt : ", e);
- return DEX_OPT_FAILED;
}
}
}
return DEX_OPT_SKIPPED;
}
- private String getAppInstructionSet(ApplicationInfo info) {
- String instructionSet = getPreferredInstructionSet();
-
- if (info.cpuAbi != null) {
- instructionSet = VMRuntime.getInstructionSet(info.cpuAbi);
+ private static String[] getAppDexInstructionSets(ApplicationInfo info) {
+ if (info.primaryCpuAbi != null) {
+ if (info.secondaryCpuAbi != null) {
+ return new String[] {
+ VMRuntime.getInstructionSet(info.primaryCpuAbi),
+ VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
+ } else {
+ return new String[] {
+ VMRuntime.getInstructionSet(info.primaryCpuAbi) };
+ }
}
- return instructionSet;
+ return new String[] { getPreferredInstructionSet() };
}
- private String getAppInstructionSetFromSettings(PackageSetting ps) {
- String instructionSet = getPreferredInstructionSet();
-
- if (ps.cpuAbiString != null) {
- instructionSet = VMRuntime.getInstructionSet(ps.cpuAbiString);
+ private static String[] getAppDexInstructionSets(PackageSetting ps) {
+ if (ps.primaryCpuAbiString != null) {
+ if (ps.secondaryCpuAbiString != null) {
+ return new String[] { ps.primaryCpuAbiString, ps.secondaryCpuAbiString };
+ } else {
+ return new String[] { ps.primaryCpuAbiString };
+ }
}
- return instructionSet;
+ return new String[] { getPreferredInstructionSet() };
}
private static String getPreferredInstructionSet() {
@@ -4726,7 +4727,7 @@
} else {
done = null;
}
- return performDexOptLI(pkg, null /* instruction set override */, forceDex, defer, done);
+ return performDexOptLI(pkg, null /* target instruction sets */, forceDex, defer, done);
}
private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
@@ -4790,12 +4791,6 @@
}
}
- final File nativeLibraryFile = new File(mAppLibInstallDir, packageName);
- NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
- if (!nativeLibraryFile.delete()) {
- Slog.w(TAG, "Couldn't delete native library directory " + nativeLibraryFile.getPath());
- }
-
return res;
}
@@ -4827,7 +4822,7 @@
// Fix that up here.
if (isSystemApp(pkg)) {
PackageSetting ps = mSettings.mPackages.get(pkg.applicationInfo.packageName);
- setInternalAppNativeLibraryPath(pkg, ps);
+ setBundledAppAbisAndRoots(pkg, ps);
}
if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
@@ -5064,8 +5059,9 @@
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
- destResourceFile, pkg.applicationInfo.nativeLibraryDir,
- pkg.applicationInfo.cpuAbi,
+ destResourceFile, pkg.applicationInfo.legacyNativeLibraryDir,
+ pkg.applicationInfo.primaryCpuAbi,
+ pkg.applicationInfo.secondaryCpuAbi,
pkg.applicationInfo.flags, user, false);
if (pkgSetting == null) {
Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
@@ -5289,6 +5285,7 @@
+ pkg.applicationInfo.uid + "/fs_"
+ currentUid;
pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
+ pkg.applicationInfo.legacyNativeLibraryDir = pkg.applicationInfo.dataDir;
String msg = "Package " + pkg.packageName
+ " has mismatched uid: "
+ currentUid + " on disk, "
@@ -5320,6 +5317,7 @@
pkg.applicationInfo.seinfo);
if (ret < 0) {
// Error from installer
+ Slog.w(TAG, "Unable to create data dirs [errorCode=" + ret + "]");
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
@@ -5332,158 +5330,185 @@
}
}
- /*
- * Set the data dir to the default "/data/data/<package name>/lib"
- * if we got here without anyone telling us different (e.g., apps
- * stored on SD card have their native libraries stored in the ASEC
- * container with the APK).
- *
- * This happens during an upgrade from a package settings file that
- * doesn't have a native library path attribute at all.
- */
- if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
- if (pkgSetting.nativeLibraryPathString == null) {
- setInternalAppNativeLibraryPath(pkg, pkgSetting);
- } else {
- pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
- }
- }
pkgSetting.uidError = uidError;
}
final String path = scanFile.getPath();
- /* Note: We don't want to unpack the native binaries for
- * system applications, unless they have been updated
- * (the binaries are already under /system/lib).
- * Also, don't unpack libs for apps on the external card
- * since they should have their libraries in the ASEC
- * container already.
- *
- * In other words, we're going to unpack the binaries
- * only for non-system apps and system app upgrades.
- */
- if (pkg.applicationInfo.nativeLibraryDir != null) {
+ final String codePath = pkg.applicationInfo.getCodePath();
+ if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
+ // For the case where we had previously uninstalled an update, get rid
+ // of any native binaries we might have unpackaged. Note that this assumes
+ // that system app updates were not installed via ASEC.
+ //
+ // TODO(multiArch): Is this cleanup really necessary ?
+ NativeLibraryHelper.removeNativeBinariesFromDirLI(
+ new File(codePath, LIB_DIR_NAME), false /* delete dirs */);
+ setBundledAppAbisAndRoots(pkg, pkgSetting);
+ } else {
+ // TODO: We can probably be smarter about this stuff. For installed apps,
+ // we can calculate this information at install time once and for all. For
+ // system apps, we can probably assume that this information doesn't change
+ // after the first boot scan. As things stand, we do lots of unnecessary work.
+
+ final boolean isAsec = isForwardLocked(pkg) || isExternal(pkg);
+ final String nativeLibraryRootStr;
+ final boolean useIsaSpecificSubdirs;
+ if (pkg.applicationInfo.legacyNativeLibraryDir != null) {
+ nativeLibraryRootStr = pkg.applicationInfo.legacyNativeLibraryDir;
+ useIsaSpecificSubdirs = false;
+ } else {
+ nativeLibraryRootStr = new File(pkg.codePath, LIB_DIR_NAME).getAbsolutePath();
+ useIsaSpecificSubdirs = true;
+ }
+
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(scanFile);
- // Enable gross and lame hacks for apps that are built with old
- // SDK tools. We must scan their APKs for renderscript bitcode and
- // not launch them if it's present. Don't bother checking on devices
- // that don't have 64 bit support.
- String[] abiList = Build.SUPPORTED_ABIS;
- boolean hasLegacyRenderscriptBitcode = false;
- if (abiOverride != null) {
- abiList = new String[] { abiOverride };
- } else if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
- NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
- abiList = Build.SUPPORTED_32_BIT_ABIS;
- hasLegacyRenderscriptBitcode = true;
- }
+ // TODO(multiArch): This can be null for apps that didn't go through the
+ // usual installation process. We can calculate it again, like we
+ // do during install time.
+ //
+ // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
+ // unnecessary.
+ final File nativeLibraryRoot = new File(nativeLibraryRootStr);
- File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- final String dataPathString = dataPath.getCanonicalPath();
-
- if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
- /*
- * Upgrading from a previous version of the OS sometimes
- * leaves native libraries in the /data/data/<app>/lib
- * directory for system apps even when they shouldn't be.
- * Recent changes in the JNI library search path
- * necessitates we remove those to match previous behavior.
- */
- if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
- Log.i(TAG, "removed obsolete native libraries for system package "
- + path);
+ // Null out the abis so that they can be recalculated.
+ pkg.applicationInfo.primaryCpuAbi = null;
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ if (isMultiArch(pkg.applicationInfo)) {
+ // Warn if we've set an abiOverride for multi-lib packages..
+ // By definition, we need to copy both 32 and 64 bit libraries for
+ // such packages.
+ if (abiOverride != null) {
+ Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
}
- if (abiOverride != null || hasLegacyRenderscriptBitcode) {
- pkg.applicationInfo.cpuAbi = abiList[0];
- pkgSetting.cpuAbiString = abiList[0];
- } else {
- setInternalAppAbi(pkg, pkgSetting);
+
+ int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
+ int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ if (isAsec) {
+ abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
+ } else {
+ abi32 = copyNativeLibrariesForInternalApp(handle,
+ nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, useIsaSpecificSubdirs);
+ }
+ }
+
+ if (abi32 < 0 && abi32 != PackageManager.NO_NATIVE_LIBRARIES) {
+ Slog.w(TAG, "Error unpackaging 32 bit native libs for multiarch app, errorCode=" + abi32);
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ if (isAsec) {
+ abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
+ } else {
+ abi64 = copyNativeLibrariesForInternalApp(handle,
+ nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, useIsaSpecificSubdirs);
+ }
+ }
+
+ if (abi64 < 0 && abi64 != PackageManager.NO_NATIVE_LIBRARIES) {
+ Slog.w(TAG, "Error unpackaging 64 bit native libs for multiarch app, errorCode=" + abi32);
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
+
+
+ if (abi64 >= 0) {
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+ }
+
+ if (abi32 >= 0) {
+ final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+ if (abi64 >= 0) {
+ pkg.applicationInfo.secondaryCpuAbi = abi;
+ } else {
+ pkg.applicationInfo.primaryCpuAbi = abi;
+ }
}
} else {
- if (!isForwardLocked(pkg) && !isExternal(pkg)) {
- /*
- * Update native library dir if it starts with
- * /data/data
- */
- if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
- setInternalAppNativeLibraryPath(pkg, pkgSetting);
- nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- }
+ String[] abiList = (abiOverride != null) ?
+ new String[] { abiOverride } : Build.SUPPORTED_ABIS;
- try {
- int copyRet = copyNativeLibrariesForInternalApp(handle,
- nativeLibraryDir, abiList);
- if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
- Slog.e(TAG, "Unable to copy native libraries");
- mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- return null;
- }
-
- // We've successfully copied native libraries across, so we make a
- // note of what ABI we're using
- if (copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
- pkg.applicationInfo.cpuAbi = abiList[copyRet];
- } else if (abiOverride != null || hasLegacyRenderscriptBitcode) {
- pkg.applicationInfo.cpuAbi = abiList[0];
- } else {
- pkg.applicationInfo.cpuAbi = null;
- }
- } catch (IOException e) {
- Slog.e(TAG, "Unable to copy native libraries", e);
- mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- return null;
- }
- } else {
- // We don't have to copy the shared libraries if we're in the ASEC container
- // but we still need to scan the file to figure out what ABI the app needs.
- //
- // TODO: This duplicates work done in the default container service. It's possible
- // to clean this up but we'll need to change the interface between this service
- // and IMediaContainerService (but doing so will spread this logic out, rather
- // than centralizing it).
- final int abi = NativeLibraryHelper.findSupportedAbi(handle, abiList);
- if (abi >= 0) {
- pkg.applicationInfo.cpuAbi = abiList[abi];
- } else if (abi == PackageManager.NO_NATIVE_LIBRARIES) {
- // Note that (non upgraded) system apps will not have any native
- // libraries bundled in their APK, but we're guaranteed not to be
- // such an app at this point.
- if (abiOverride != null || hasLegacyRenderscriptBitcode) {
- pkg.applicationInfo.cpuAbi = abiList[0];
- } else {
- pkg.applicationInfo.cpuAbi = null;
- }
- } else {
- mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- return null;
- }
+ // Enable gross and lame hacks for apps that are built with old
+ // SDK tools. We must scan their APKs for renderscript bitcode and
+ // not launch them if it's present. Don't bother checking on devices
+ // that don't have 64 bit support.
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && abiOverride == null &&
+ NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
}
- if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
- final int[] userIds = sUserManager.getUserIds();
- synchronized (mInstallLock) {
- for (int userId : userIds) {
- if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
- pkg.applicationInfo.nativeLibraryDir, userId) < 0) {
- Slog.w(TAG, "Failed linking native library dir (user=" + userId
- + ")");
- mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- return null;
- }
- }
+ final int copyRet;
+ if (isAsec) {
+ copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+ } else {
+ copyRet = copyNativeLibrariesForInternalApp(handle, nativeLibraryRoot, abiList,
+ useIsaSpecificSubdirs);
+ }
+
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+ Slog.w(TAG, "Error unpackaging native libs for app, errorCode=" + copyRet);
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
+
+ if (copyRet >= 0) {
+ pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
}
}
-
- pkgSetting.cpuAbiString = pkg.applicationInfo.cpuAbi;
} catch (IOException ioe) {
Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
} finally {
IoUtils.closeQuietly(handle);
}
+
+ if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
+ final int[] userIds = sUserManager.getUserIds();
+ synchronized (mInstallLock) {
+ // Create a native library symlink only if we have native libraries
+ // and if the native libraries are 32 bit libraries. We do not provide
+ // this symlink for 64 bit libraries.
+ if (pkg.applicationInfo.primaryCpuAbi != null &&
+ !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
+ final String nativeLibPath;
+ if (pkg.applicationInfo.legacyNativeLibraryDir != null) {
+ nativeLibPath = pkg.applicationInfo.legacyNativeLibraryDir;
+ } else {
+ nativeLibPath = new File(nativeLibraryRootStr,
+ VMRuntime.getInstructionSet(pkg.applicationInfo.primaryCpuAbi)).getAbsolutePath();
+ }
+
+ for (int userId : userIds) {
+ if (mInstaller.linkNativeLibraryDirectory(pkg.packageName, nativeLibPath, userId) < 0) {
+ Slog.w(TAG, "Failed linking native library dir (user=" + userId
+ + ")");
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
+ }
+ }
+ }
+
+ pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
+ pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
}
+ if (DEBUG_ABI_SELECTION) {
+ Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" +
+ " primary=" + pkg.applicationInfo.primaryCpuAbi +
+ " secondary=" + pkg.applicationInfo.secondaryCpuAbi);
+ }
+
+ // Check if we have a legacy native library path, use it if we do.
+ pkg.applicationInfo.legacyNativeLibraryDir = pkgSetting.legacyNativeLibraryPathString;
+
+ // Now that we've calculated the ABIs and determined if it's an internal app,
+ // we will go ahead and populate the nativeLibraryPath.
+ populateDefaultNativeLibraryPath(pkg, pkg.applicationInfo);
+
if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
@@ -5929,6 +5954,9 @@
a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
a.info.dataDir = pkg.applicationInfo.dataDir;
+
+ // TODO: Update instrumentation.nativeLibraryDir as well ? Does it
+ // need other information about the application, like the ABI and what not ?
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
@@ -5989,13 +6017,16 @@
* match {@code scannedPackage} or will update the ABI of {@code scannedPackage} to match
* the ABI selected for {@code packagesForUser}. This variant is used when installing or
* updating a package that belongs to a shared user.
+ *
+ * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+ * adds unnecessary complexity.
*/
private boolean adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt) {
String requiredInstructionSet = null;
- if (scannedPackage != null && scannedPackage.applicationInfo.cpuAbi != null) {
+ if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
requiredInstructionSet = VMRuntime.getInstructionSet(
- scannedPackage.applicationInfo.cpuAbi);
+ scannedPackage.applicationInfo.primaryCpuAbi);
}
PackageSetting requirer = null;
@@ -6005,11 +6036,11 @@
// we will never be able to change the ABI of any package belonging to a shared
// user, even if it's compatible with other packages.
if (scannedPackage == null || ! scannedPackage.packageName.equals(ps.name)) {
- if (ps.cpuAbiString == null) {
+ if (ps.primaryCpuAbiString == null) {
continue;
}
- final String instructionSet = VMRuntime.getInstructionSet(ps.cpuAbiString);
+ final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
if (requiredInstructionSet != null) {
if (!instructionSet.equals(requiredInstructionSet)) {
// We have a mismatch between instruction sets (say arm vs arm64).
@@ -6037,30 +6068,30 @@
// requirer != null implies that either scannedPackage was null or that scannedPackage
// did not require an ABI, in which case we have to adjust scannedPackage to match
// the ABI of the set (which is the same as requirer's ABI)
- adjustedAbi = requirer.cpuAbiString;
+ adjustedAbi = requirer.primaryCpuAbiString;
if (scannedPackage != null) {
- scannedPackage.applicationInfo.cpuAbi = adjustedAbi;
+ scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
}
} else {
// requirer == null implies that we're updating all ABIs in the set to
// match scannedPackage.
- adjustedAbi = scannedPackage.applicationInfo.cpuAbi;
+ adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
}
for (PackageSetting ps : packagesForUser) {
if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
- if (ps.cpuAbiString != null) {
+ if (ps.primaryCpuAbiString != null) {
continue;
}
- ps.cpuAbiString = adjustedAbi;
+ ps.primaryCpuAbiString = adjustedAbi;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
- ps.pkg.applicationInfo.cpuAbi = adjustedAbi;
+ ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
if (performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true) == DEX_OPT_FAILED) {
- ps.cpuAbiString = null;
- ps.pkg.applicationInfo.cpuAbi = null;
+ ps.primaryCpuAbiString = null;
+ ps.pkg.applicationInfo.primaryCpuAbi = null;
return false;
} else {
mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
@@ -6097,7 +6128,7 @@
}
}
- private String calculateApkRoot(final String codePathString) {
+ private static String calculateApkRoot(final String codePathString) {
final File codePath = new File(codePathString);
final File codeRoot;
if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
@@ -6121,7 +6152,7 @@
Slog.w(TAG, "Unrecognized code path "
+ codePath + " - using " + codeRoot);
} catch (IOException e) {
- // Can't canonicalize the lib path -- shenanigans?
+ // Can't canonicalize the code path -- shenanigans?
Slog.w(TAG, "Can't canonicalize code path " + codePath);
return Environment.getRootDirectory().getPath();
}
@@ -6129,104 +6160,154 @@
return codeRoot.getPath();
}
- // This is the initial scan-time determination of how to handle a given
- // package for purposes of native library location.
- private void setInternalAppNativeLibraryPath(PackageParser.Package pkg,
- PackageSetting pkgSetting) {
- // "bundled" here means system-installed with no overriding update
- final boolean bundledApk = isSystemApp(pkg) && !isUpdatedSystemApp(pkg);
- final File codeFile = new File(pkg.applicationInfo.getCodePath());
- final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
-
- String nativeLibraryPath = null;
- if (bundledApk) {
- // If "/system/lib64/apkname" exists, assume that is the per-package
- // native library directory to use; otherwise use "/system/lib/apkname".
- String apkRoot = calculateApkRoot(pkg.applicationInfo.getCodePath());
- File lib64 = new File(apkRoot, LIB64_DIR_NAME);
- File packLib64 = new File(lib64, apkName);
- File libDir = (packLib64.exists()) ? lib64 : new File(apkRoot, LIB_DIR_NAME);
- nativeLibraryPath = (new File(libDir, apkName)).getAbsolutePath();
- } else if (isApkFile(codeFile)) {
- // Monolithic install
- nativeLibraryPath = (new File(mAppLibInstallDir, apkName)).getAbsolutePath();
- } else {
- // Cluster install
- // TODO: pipe through abiOverride
- String[] abiList = Build.SUPPORTED_ABIS;
- NativeLibraryHelper.Handle handle = null;
- try {
- handle = NativeLibraryHelper.Handle.create(codeFile);
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
- NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
- abiList = Build.SUPPORTED_32_BIT_ABIS;
- }
-
- final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList);
- if (abiIndex >= 0) {
- final File baseLibFile = new File(codeFile, LIB_DIR_NAME);
- final String abi = Build.SUPPORTED_ABIS[abiIndex];
- final String instructionSet = VMRuntime.getInstructionSet(abi);
- nativeLibraryPath = new File(baseLibFile, instructionSet).getAbsolutePath();
- }
- } catch (IOException e) {
- Slog.e(TAG, "Failed to detect native libraries", e);
- } finally {
- IoUtils.closeQuietly(handle);
+ private void populateDefaultNativeLibraryPath(PackageParser.Package pkg,
+ ApplicationInfo info) {
+ if (info.legacyNativeLibraryDir != null) {
+ // Not a cluster install.
+ if (DEBUG_ABI_SELECTION) {
+ Log.i(TAG, "Set nativeLibraryDir [non_cluster] for: " + pkg.packageName +
+ " to " + info.legacyNativeLibraryDir);
}
- }
- pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
- // pkgSetting might be null during rescan following uninstall of updates
- // to a bundled app, so accommodate that possibility. The settings in
- // that case will be established later from the parsed package.
- if (pkgSetting != null) {
- pkgSetting.nativeLibraryPathString = nativeLibraryPath;
+ info.nativeLibraryDir = info.legacyNativeLibraryDir;
+ } else if (info.primaryCpuAbi != null) {
+ final boolean is64Bit = VMRuntime.is64BitAbi(info.primaryCpuAbi);
+ if (info.apkRoot != null) {
+ // This is a bundled system app so choose the path based on the ABI.
+ // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
+ // is just the default path.
+ final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+ final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
+ info.nativeLibraryDir = (new File(info.apkRoot, new File(libDir, apkName).getAbsolutePath()))
+ .getAbsolutePath();
+
+ if (DEBUG_ABI_SELECTION) {
+ Log.i(TAG, "Set nativeLibraryDir [system] for: " + pkg.packageName +
+ " to " + info.nativeLibraryDir);
+ }
+ } else {
+ // Cluster install. legacyNativeLibraryDir == null && primaryCpuAbi = null
+ // implies this must be a cluster package.
+ final String codePath = pkg.codePath;
+ final File libPath = new File(new File(codePath, LIB_DIR_NAME),
+ VMRuntime.getInstructionSet(info.primaryCpuAbi));
+ info.nativeLibraryDir = libPath.getAbsolutePath();
+
+ if (DEBUG_ABI_SELECTION) {
+ Log.i(TAG, "Set nativeLibraryDir [cluster] for: " + pkg.packageName +
+ " to " + info.nativeLibraryDir);
+ }
+ }
+ } else {
+ if (DEBUG_ABI_SELECTION) {
+ Log.i(TAG, "Setting nativeLibraryDir to null for: " + pkg.packageName);
+ }
+
+ info.nativeLibraryDir = null;
}
}
- // Deduces the required ABI of an upgraded system app.
- private void setInternalAppAbi(PackageParser.Package pkg, PackageSetting pkgSetting) {
- final String apkRoot = calculateApkRoot(pkg.applicationInfo.getCodePath());
+ /**
+ * Calculate the abis and roots for a bundled app. These can uniquely
+ * be determined from the contents of the system partition, i.e whether
+ * it contains 64 or 32 bit shared libraries etc. We do not validate any
+ * of this information, and instead assume that the system was built
+ * sensibly.
+ */
+ private void setBundledAppAbisAndRoots(PackageParser.Package pkg,
+ PackageSetting pkgSetting) {
final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir);
+ pkg.applicationInfo.apkRoot = apkRoot;
+ setBundledAppAbi(pkg, apkRoot, apkName);
+ // pkgSetting might be null during rescan following uninstall of updates
+ // to a bundled app, so accommodate that possibility. The settings in
+ // that case will be established later from the parsed package.
+ //
+ // If the settings aren't null, sync them up with what we've just derived.
+ // note that apkRoot isn't stored in the package settings.
+ if (pkgSetting != null) {
+ pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
+ pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+ }
+ }
+
+ /**
+ * Deduces the ABI of a bundled app and sets the relevant fields on the
+ * parsed pkg object.
+ *
+ * @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}
+ * under which system libraries are installed.
+ * @param apkName the name of the installed package.
+ */
+ private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
// This is of the form "/system/lib64/<packagename>", "/vendor/lib64/<packagename>"
// or similar.
- final File lib64 = new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath());
- final File lib = new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath());
+ final boolean has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
+ final boolean has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
- // Assume that the bundled native libraries always correspond to the
- // most preferred 32 or 64 bit ABI.
- if (lib64.exists()) {
- pkg.applicationInfo.cpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkgSetting.cpuAbiString = Build.SUPPORTED_64_BIT_ABIS[0];
- } else if (lib.exists()) {
- pkg.applicationInfo.cpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkgSetting.cpuAbiString = Build.SUPPORTED_32_BIT_ABIS[0];
+ if (has64BitLibs && !has32BitLibs) {
+ // The package has 64 bit libs, but not 32 bit libs. Its primary
+ // ABI should be 64 bit. We can safely assume here that the bundled
+ // native libraries correspond to the most preferred ABI in the list.
+
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ } else if (has32BitLibs && !has64BitLibs) {
+ // The package has 32 bit libs but not 64 bit libs. Its primary
+ // ABI should be 32 bit.
+
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ } else if (has32BitLibs && has64BitLibs) {
+ // The application has both 64 and 32 bit bundled libraries. We check
+ // here that the app declares multiArch support, and warn if it doesn't.
+ //
+ // We will be lenient here and record both ABIs. The primary will be the
+ // ABI that's higher on the list, i.e, a device that's configured to prefer
+ // 64 bit apps will see a 64 bit primary ABI,
+
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+ Slog.e(TAG, "Package: " + pkg + " has multiple bundled libs, but is not multiarch.");
+ }
+
+ if (VMRuntime.is64BitAbi(getPreferredInstructionSet())) {
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ } else {
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ }
} else {
- // This is the case where the app has no native code.
- pkg.applicationInfo.cpuAbi = null;
- pkgSetting.cpuAbiString = null;
+ pkg.applicationInfo.primaryCpuAbi = null;
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ }
+ }
+
+ private static void createNativeLibrarySubdir(File path) throws IOException {
+ if (!path.isDirectory()) {
+ path.delete();
+
+ if (!path.mkdir()) {
+ throw new IOException("Cannot create " + path.getPath());
+ }
+
+ try {
+ Os.chmod(path.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ } catch (ErrnoException e) {
+ throw new IOException("Cannot chmod native library directory "
+ + path.getPath(), e);
+ }
+ } else if (!SELinux.restorecon(path)) {
+ throw new IOException("Cannot set SELinux context for " + path.getPath());
}
}
private static int copyNativeLibrariesForInternalApp(NativeLibraryHelper.Handle handle,
- final File nativeLibraryDir, String[] abiList) throws IOException {
- if (!nativeLibraryDir.isDirectory()) {
- nativeLibraryDir.delete();
-
- if (!nativeLibraryDir.mkdir()) {
- throw new IOException("Cannot create " + nativeLibraryDir.getPath());
- }
-
- try {
- Os.chmod(nativeLibraryDir.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
- } catch (ErrnoException e) {
- throw new IOException("Cannot chmod native library directory "
- + nativeLibraryDir.getPath(), e);
- }
- } else if (!SELinux.restorecon(nativeLibraryDir)) {
- throw new IOException("Cannot set SELinux context for " + nativeLibraryDir.getPath());
- }
+ final File nativeLibraryRoot, String[] abiList, boolean useIsaSubdir) throws IOException {
+ createNativeLibrarySubdir(nativeLibraryRoot);
/*
* If this is an internal application or our nativeLibraryPath points to
@@ -6234,8 +6315,22 @@
*/
int abi = NativeLibraryHelper.findSupportedAbi(handle, abiList);
if (abi >= 0) {
+ /*
+ * If we have a matching instruction set, construct a subdir under the native
+ * library root that corresponds to this instruction set.
+ */
+ final String instructionSet = VMRuntime.getInstructionSet(abiList[abi]);
+ final File subDir;
+ if (useIsaSubdir) {
+ final File isaSubdir = new File(nativeLibraryRoot, instructionSet);
+ createNativeLibrarySubdir(isaSubdir);
+ subDir = isaSubdir;
+ } else {
+ subDir = nativeLibraryRoot;
+ }
+
int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
- nativeLibraryDir, Build.SUPPORTED_ABIS[abi]);
+ subDir, Build.SUPPORTED_ABIS[abi]);
if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
return copyRet;
}
@@ -8374,7 +8469,7 @@
private InstallArgs mArgs;
private int mRet;
final String packageAbiOverride;
- final String packageInstructionSetOverride;
+ boolean multiArch;
InstallParams(File originFile, boolean originStaged, IPackageInstallObserver2 observer,
int flags, String installerPackageName, VerificationParams verificationParams,
@@ -8387,8 +8482,6 @@
this.installerPackageName = installerPackageName;
this.verificationParams = verificationParams;
this.packageAbiOverride = packageAbiOverride;
- this.packageInstructionSetOverride = (packageAbiOverride == null) ?
- packageAbiOverride : VMRuntime.getInstructionSet(packageAbiOverride);
}
@Override
@@ -8499,6 +8592,11 @@
final String originPath = originFile.getAbsolutePath();
pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags, lowThreshold,
packageAbiOverride);
+ // Keep track of whether this package is a multiArch package until
+ // we perform a full scan of it. We need to do this because we might
+ // end up extracting the package shared libraries before we perform
+ // a full scan.
+ multiArch = pkgLite.multiArch;
/*
* If we have too little free space, try to free cache
@@ -8744,7 +8842,8 @@
int mRet;
MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags,
- String packageName, String instructionSet, int uid, UserHandle user) {
+ String packageName, String[] instructionSets, int uid, UserHandle user,
+ boolean isMultiArch) {
super(user);
this.srcArgs = srcArgs;
this.observer = observer;
@@ -8754,7 +8853,7 @@
if (srcArgs != null) {
final String codePath = srcArgs.getCodePath();
targetArgs = createInstallArgsForMoveTarget(codePath, flags, packageName,
- instructionSet);
+ instructionSets, isMultiArch);
} else {
targetArgs = null;
}
@@ -8869,7 +8968,8 @@
* when cleaning up old installs, or used as a move source.
*/
private InstallArgs createInstallArgsForExisting(int flags, String codePath,
- String resourcePath, String nativeLibraryPath, String instructionSet) {
+ String resourcePath, String nativeLibraryRoot, String[] instructionSets,
+ boolean isMultiArch) {
final boolean isInAsec;
if (installOnSd(flags)) {
/* Apps on SD card are always in ASEC containers. */
@@ -8886,23 +8986,24 @@
}
if (isInAsec) {
- return new AsecInstallArgs(codePath, resourcePath, nativeLibraryPath,
- instructionSet, installOnSd(flags), installForwardLocked(flags));
+ return new AsecInstallArgs(codePath, instructionSets,
+ installOnSd(flags), installForwardLocked(flags), isMultiArch);
} else {
- return new FileInstallArgs(codePath, resourcePath, nativeLibraryPath, instructionSet);
+ return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot,
+ instructionSets, isMultiArch);
}
}
private InstallArgs createInstallArgsForMoveTarget(String codePath, int flags, String pkgName,
- String instructionSet) {
+ String[] instructionSets, boolean isMultiArch) {
final File codeFile = new File(codePath);
if (installOnSd(flags) || installForwardLocked(flags)) {
String cid = getNextCodePath(codePath, pkgName, "/"
+ AsecInstallArgs.RES_FILE_NAME);
- return new AsecInstallArgs(codeFile, cid, instructionSet, installOnSd(flags),
- installForwardLocked(flags));
+ return new AsecInstallArgs(codeFile, cid, instructionSets, installOnSd(flags),
+ installForwardLocked(flags), isMultiArch);
} else {
- return new FileInstallArgs(codeFile, instructionSet);
+ return new FileInstallArgs(codeFile, instructionSets, isMultiArch);
}
}
@@ -8920,12 +9021,18 @@
final String installerPackageName;
final ManifestDigest manifestDigest;
final UserHandle user;
- final String instructionSet;
final String abiOverride;
+ final boolean multiArch;
+
+ // The list of instruction sets supported by this app. This is currently
+ // only used during the rmdex() phase to clean up resources. We can get rid of this
+ // if we move dex files under the common app path.
+ /* nullable */ String[] instructionSets;
InstallArgs(File originFile, boolean originStaged, IPackageInstallObserver2 observer,
- int flags, String installerPackageName, ManifestDigest manifestDigest,
- UserHandle user, String instructionSet, String abiOverride) {
+ int flags, String installerPackageName, ManifestDigest manifestDigest,
+ UserHandle user, String[] instructionSets,
+ String abiOverride, boolean multiArch) {
this.originFile = originFile;
this.originStaged = originStaged;
this.flags = flags;
@@ -8933,8 +9040,9 @@
this.installerPackageName = installerPackageName;
this.manifestDigest = manifestDigest;
this.user = user;
- this.instructionSet = instructionSet;
+ this.instructionSets = instructionSets;
this.abiOverride = abiOverride;
+ this.multiArch = multiArch;
}
abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
@@ -8951,8 +9059,7 @@
abstract String getCodePath();
/** @see PackageSettingBase#resourcePathString */
abstract String getResourcePath();
- /** @see PackageSettingBase#nativeLibraryPathString */
- abstract String getNativeLibraryPath();
+ abstract String getLegacyNativeLibraryPath();
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
@@ -8995,7 +9102,7 @@
class FileInstallArgs extends InstallArgs {
private File codeFile;
private File resourceFile;
- private File nativeLibraryFile;
+ private File legacyNativeLibraryPath;
// Example topology:
// /data/app/com.example/base.apk
@@ -9008,24 +9115,27 @@
FileInstallArgs(InstallParams params) {
super(params.originFile, params.originStaged, params.observer, params.flags,
params.installerPackageName, params.getManifestDigest(), params.getUser(),
- params.packageInstructionSetOverride, params.packageAbiOverride);
+ null /* instruction sets */, params.packageAbiOverride,
+ params.multiArch);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
}
/** Existing install */
- FileInstallArgs(String codePath, String resourcePath, String nativeLibraryPath,
- String instructionSet) {
- super(null, false, null, 0, null, null, null, instructionSet, null);
+ FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryRoot,
+ String[] instructionSets, boolean isMultiArch) {
+ super(null, false, null, 0, null, null, null, instructionSets, null, isMultiArch);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
- this.nativeLibraryFile = (nativeLibraryPath != null) ? new File(nativeLibraryPath) : null;
+ this.legacyNativeLibraryPath = (legacyNativeLibraryRoot != null) ?
+ new File(legacyNativeLibraryRoot) : null;
}
/** New install from existing */
- FileInstallArgs(File originFile, String instructionSet) {
- super(originFile, false, null, 0, null, null, null, instructionSet, null);
+ FileInstallArgs(File originFile, String[] instructionSets, boolean isMultiArch) {
+ super(originFile, false, null, 0, null, null, null, instructionSets, null,
+ isMultiArch);
}
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
@@ -9091,35 +9201,67 @@
}
}
- String[] abiList = (abiOverride != null) ?
- new String[] { abiOverride } : Build.SUPPORTED_ABIS;
+ final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
- abiOverride == null &&
- NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
- abiList = Build.SUPPORTED_32_BIT_ABIS;
+ if (multiArch) {
+ // Warn if we've set an abiOverride for multi-lib packages..
+ // By definition, we need to copy both 32 and 64 bit libraries for
+ // such packages.
+ if (abiOverride != null) {
+ Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
+ }
+
+ int copyRet = PackageManager.NO_NATIVE_LIBRARIES;
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ copyRet = copyNativeLibrariesForInternalApp(handle, libraryRoot,
+ Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */);
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+ Slog.w(TAG, "Failure copying 32 bit native libraries [errorCode=" + copyRet + "]");
+ return copyRet;
+ }
+ }
+
+ if (DEBUG_ABI_SELECTION && copyRet >= 0) {
+ Log.d(TAG, "Installed 32 bit libraries under: " + codeFile + " abi=" +
+ Build.SUPPORTED_32_BIT_ABIS[copyRet]);
+ }
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ copyRet = copyNativeLibrariesForInternalApp(handle, libraryRoot,
+ Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */);
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+ Slog.w(TAG, "Failure copying 64 bit native libraries [errorCode=" + copyRet + "]");
+ return copyRet;
+ }
+ }
+
+ if (DEBUG_ABI_SELECTION && copyRet >= 0) {
+ Log.d(TAG, "Installed 64 bit libraries under: " + codeFile + " abi=" +
+ Build.SUPPORTED_64_BIT_ABIS[copyRet]);
+ }
+ } else {
+ String[] abiList = (abiOverride != null) ?
+ new String[] { abiOverride } : Build.SUPPORTED_ABIS;
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && abiOverride == null &&
+ NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
+ }
+
+ int copyRet = copyNativeLibrariesForInternalApp(handle, libraryRoot, abiList,
+ true /* use isa specific subdirs */);
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+ Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]");
+ return copyRet;
+ }
+
+ if (DEBUG_ABI_SELECTION && copyRet >= 0) {
+ Log.d(TAG, "Installed libraries under: " + codeFile + " abi=" + abiList[copyRet]);
+ }
}
-
- // TODO: refactor to avoid double findSupportedAbi()
- final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList);
- if (abiIndex < 0 && abiIndex != PackageManager.NO_NATIVE_LIBRARIES) {
- return abiIndex;
- } else if (abiIndex >= 0) {
- final File baseLibFile = new File(codeFile, LIB_DIR_NAME);
- baseLibFile.mkdir();
- Os.chmod(baseLibFile.getAbsolutePath(), 0755);
-
- final String abi = Build.SUPPORTED_ABIS[abiIndex];
- final String instructionSet = VMRuntime.getInstructionSet(abi);
- nativeLibraryFile = new File(baseLibFile, instructionSet);
- nativeLibraryFile.mkdir();
- Os.chmod(nativeLibraryFile.getAbsolutePath(), 0755);
-
- copyNativeLibrariesForInternalApp(handle, nativeLibraryFile, abiList);
- }
- } catch (IOException | ErrnoException e) {
+ } catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
@@ -9156,8 +9298,6 @@
// Reflect the rename internally
codeFile = afterCodeFile;
resourceFile = afterCodeFile;
- nativeLibraryFile = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
- nativeLibraryFile);
// Reflect the rename in scanned details
pkg.codePath = afterCodeFile.getAbsolutePath();
@@ -9173,7 +9313,8 @@
pkg.applicationInfo.setResourcePath(pkg.codePath);
pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
- pkg.applicationInfo.nativeLibraryDir = getNativeLibraryPath();
+ // Null out the legacy native dir so we stop using it.
+ pkg.applicationInfo.legacyNativeLibraryDir = null;
return true;
}
@@ -9197,8 +9338,8 @@
}
@Override
- String getNativeLibraryPath() {
- return (nativeLibraryFile != null) ? nativeLibraryFile.getAbsolutePath() : null;
+ String getLegacyNativeLibraryPath() {
+ return (legacyNativeLibraryPath != null) ? legacyNativeLibraryPath.getAbsolutePath() : null;
}
private boolean cleanUp() {
@@ -9215,9 +9356,11 @@
resourceFile.delete();
}
- if (nativeLibraryFile != null && !FileUtils.contains(codeFile, nativeLibraryFile)) {
- FileUtils.deleteContents(nativeLibraryFile);
- nativeLibraryFile.delete();
+ if (legacyNativeLibraryPath != null && !FileUtils.contains(codeFile, legacyNativeLibraryPath)) {
+ if (!FileUtils.deleteContents(legacyNativeLibraryPath)) {
+ Slog.w(TAG, "Couldn't delete native library directory " + legacyNativeLibraryPath);
+ }
+ legacyNativeLibraryPath.delete();
}
return true;
@@ -9238,16 +9381,18 @@
cleanUp();
if (!allCodePaths.isEmpty()) {
- if (instructionSet == null) {
+ if (instructionSets == null) {
throw new IllegalStateException("instructionSet == null");
}
for (String codePath : allCodePaths) {
- int retCode = mInstaller.rmdex(codePath, instructionSet);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location " + codePath + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
+ for (String instructionSet : instructionSets) {
+ int retCode = mInstaller.rmdex(codePath, instructionSet);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location " + codePath + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
}
}
}
@@ -9289,21 +9434,22 @@
String cid;
String packagePath;
String resourcePath;
- String libraryPath;
+ String legacyNativeLibraryDir;
/** New install */
AsecInstallArgs(InstallParams params) {
super(params.originFile, params.originStaged, params.observer, params.flags,
- params.installerPackageName, params.getManifestDigest(), params.getUser(),
- params.packageInstructionSetOverride, params.packageAbiOverride);
+ params.installerPackageName, params.getManifestDigest(),
+ params.getUser(), null /* instruction sets */,
+ params.packageAbiOverride, params.multiArch);
}
/** Existing install */
- AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
- String instructionSet, boolean isExternal, boolean isForwardLocked) {
+ AsecInstallArgs(String fullCodePath, String[] instructionSets,
+ boolean isExternal, boolean isForwardLocked, boolean isMultiArch) {
super(null, false, null, (isExternal ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSet, null);
+ instructionSets, null, isMultiArch);
// Extract cid from fullCodePath
int eidx = fullCodePath.lastIndexOf("/");
String subStr1 = fullCodePath.substring(0, eidx);
@@ -9312,20 +9458,21 @@
setCachePath(subStr1);
}
- AsecInstallArgs(String cid, String instructionSet, boolean isForwardLocked) {
+ AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked,
+ boolean isMultiArch) {
super(null, false, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSet, null);
+ instructionSets, null, isMultiArch);
this.cid = cid;
setCachePath(PackageHelper.getSdDir(cid));
}
/** New install from existing */
- AsecInstallArgs(File originPackageFile, String cid, String instructionSet,
- boolean isExternal, boolean isForwardLocked) {
+ AsecInstallArgs(File originPackageFile, String cid, String[] instructionSets,
+ boolean isExternal, boolean isForwardLocked, boolean isMultiArch) {
super(originPackageFile, false, null, (isExternal ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSet, null);
+ instructionSets, null, isMultiArch);
this.cid = cid;
}
@@ -9376,8 +9523,8 @@
}
@Override
- String getNativeLibraryPath() {
- return libraryPath;
+ String getLegacyNativeLibraryPath() {
+ return legacyNativeLibraryDir;
}
int doPreInstall(int status) {
@@ -9452,14 +9599,16 @@
pkg.applicationInfo.setResourcePath(getResourcePath());
pkg.applicationInfo.setBaseResourcePath(getResourcePath());
pkg.applicationInfo.setSplitResourcePaths(null);
- pkg.applicationInfo.nativeLibraryDir = getNativeLibraryPath();
+ // ASEC installs are considered "legacy" because we don't support
+ // multiarch on them yet, and use the old style paths on them.
+ pkg.applicationInfo.legacyNativeLibraryDir = legacyNativeLibraryDir;
return true;
}
private void setCachePath(String newCachePath) {
File cachePath = new File(newCachePath);
- libraryPath = new File(cachePath, LIB_DIR_NAME).getPath();
+ legacyNativeLibraryDir = new File(cachePath, LIB_DIR_NAME).getPath();
packagePath = new File(cachePath, RES_FILE_NAME).getPath();
if (isFwdLocked()) {
@@ -9508,15 +9657,17 @@
void cleanUpResourcesLI() {
String sourceFile = getCodePath();
// Remove dex file
- if (instructionSet == null) {
+ if (instructionSets == null) {
throw new IllegalStateException("instructionSet == null");
}
- int retCode = mInstaller.rmdex(sourceFile, instructionSet);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location "
- + sourceFile.toString() + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
+ for (String instructionSet : instructionSets) {
+ int retCode = mInstaller.rmdex(sourceFile, instructionSet);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location "
+ + sourceFile.toString() + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
}
cleanUp();
}
@@ -9922,8 +10073,9 @@
res.removedInfo.args = createInstallArgsForExisting(0,
deletedPackage.applicationInfo.getCodePath(),
deletedPackage.applicationInfo.getResourcePath(),
- deletedPackage.applicationInfo.nativeLibraryDir,
- getAppInstructionSet(deletedPackage.applicationInfo));
+ deletedPackage.applicationInfo.legacyNativeLibraryDir,
+ getAppDexInstructionSets(deletedPackage.applicationInfo),
+ isMultiArch(deletedPackage.applicationInfo));
} else {
res.removedInfo.args = null;
}
@@ -9983,10 +10135,11 @@
private int moveDexFilesLI(String oldCodePath, PackageParser.Package newPackage) {
// TODO: extend to move split APK dex files
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
- int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath,
- instructionSet);
- if (retCode != 0) {
+ final String[] instructionSets = getAppDexInstructionSets(newPackage.applicationInfo);
+ for (String instructionSet : instructionSets) {
+ int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath,
+ instructionSet);
+ if (retCode != 0) {
/*
* Programs may be lazily run through dexopt, so the
* source may not exist. However, something seems to
@@ -9995,9 +10148,10 @@
* remove the target to make sure there isn't a stale
* file from a previous version of the package.
*/
- newPackage.mDexOptNeeded = true;
- mInstaller.rmdex(oldCodePath, instructionSet);
- mInstaller.rmdex(newPackage.baseCodePath, instructionSet);
+ newPackage.mDexOptNeeded = true;
+ mInstaller.rmdex(oldCodePath, instructionSet);
+ mInstaller.rmdex(newPackage.baseCodePath, instructionSet);
+ }
}
}
return PackageManager.INSTALL_SUCCEEDED;
@@ -10234,6 +10388,14 @@
return (ps.pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
}
+ private static boolean isMultiArch(PackageSetting ps) {
+ return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0;
+ }
+
+ private static boolean isMultiArch(ApplicationInfo info) {
+ return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
+ }
+
private static boolean isExternal(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
@@ -10591,7 +10753,7 @@
// Reinstate the old system package
mSettings.enableSystemPackageLPw(newPs.name);
// Remove any native libraries from the upgraded package.
- NativeLibraryHelper.removeNativeBinariesLI(newPs.nativeLibraryPathString);
+ NativeLibraryHelper.removeNativeBinariesLI(newPs.legacyNativeLibraryPathString);
}
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
@@ -10610,7 +10772,7 @@
// writer
synchronized (mPackages) {
PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);
- setInternalAppNativeLibraryPath(newPkg, ps);
+ setBundledAppAbisAndRoots(newPkg, ps);
updatePermissionsLPw(newPkg.packageName, newPkg,
UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
if (applyUserRestrictions) {
@@ -10650,8 +10812,8 @@
// Delete application code and resources
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString,
- getAppInstructionSetFromSettings(ps));
+ ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
+ getAppDexInstructionSets(ps), isMultiArch(ps));
}
return true;
}
@@ -11056,7 +11218,7 @@
}
PackageParser.Package p;
boolean dataOnly = false;
- String libDirPath = null;
+ String libDirRoot = null;
String asecPath = null;
PackageSetting ps = null;
synchronized (mPackages) {
@@ -11071,7 +11233,7 @@
p = ps.pkg;
}
if (ps != null) {
- libDirPath = ps.nativeLibraryPathString;
+ libDirRoot = ps.legacyNativeLibraryPathString;
}
if (p != null && (isExternal(p) || isForwardLocked(p))) {
String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
@@ -11092,8 +11254,12 @@
}
}
// TODO: extend to measure size of split APKs
- int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirPath,
- publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps),
+ // TODO(multiArch): Extend getSizeInfo to look at the full subdirectory tree,
+ // not just the first level.
+ // TODO(multiArch): Extend getSizeInfo to look at *all* instruction sets, not
+ // just the primary.
+ int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirRoot,
+ publicSrcDir, asecPath, getAppDexInstructionSets(ps),
pStats);
if (res < 0) {
return false;
@@ -12357,8 +12523,7 @@
}
final AsecInstallArgs args = new AsecInstallArgs(cid,
- getAppInstructionSetFromSettings(ps),
- isForwardLocked(ps));
+ getAppDexInstructionSets(ps), isForwardLocked(ps), isMultiArch(ps));
// The package status is changed only if the code path
// matches between settings and the container id.
if (ps.codePathString != null && ps.codePathString.equals(args.getCodePath())) {
@@ -12676,16 +12841,17 @@
* anyway.
*/
if (returnCode != PackageManager.MOVE_SUCCEEDED) {
- processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1, user),
+ processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1, user, false),
returnCode);
} else {
Message msg = mHandler.obtainMessage(INIT_COPY);
- final String instructionSet = getAppInstructionSet(pkg.applicationInfo);
+ final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+ final boolean multiArch = isMultiArch(pkg.applicationInfo);
InstallArgs srcArgs = createInstallArgsForExisting(currFlags,
pkg.applicationInfo.getCodePath(), pkg.applicationInfo.getResourcePath(),
- pkg.applicationInfo.nativeLibraryDir, instructionSet);
+ pkg.applicationInfo.legacyNativeLibraryDir, instructionSets, multiArch);
MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
- instructionSet, pkg.applicationInfo.uid, user);
+ instructionSets, pkg.applicationInfo.uid, user, multiArch);
msg.obj = mp;
mHandler.sendMessage(msg);
}
@@ -12747,12 +12913,15 @@
final String oldCodePath = pkg.codePath;
final String newCodePath = mp.targetArgs.getCodePath();
final String newResPath = mp.targetArgs.getResourcePath();
- final String newNativePath = mp.targetArgs
- .getNativeLibraryPath();
-
- final File newNativeDir = new File(newNativePath);
+ // TODO: This assumes the new style of installation.
+ // should we look at legacyNativeLibraryPath ?
+ final String newNativeRoot = new File(pkg.codePath, LIB_DIR_NAME).getAbsolutePath();
+ final File newNativeDir = new File(newNativeRoot);
if (!isForwardLocked(pkg) && !isExternal(pkg)) {
+ // TODO(multiArch): Fix this so that it looks at the existing
+ // recorded CPU abis from the package. There's no need for a separate
+ // round of ABI scanning here.
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(
@@ -12771,11 +12940,17 @@
IoUtils.closeQuietly(handle);
}
}
+
final int[] users = sUserManager.getUserIds();
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
for (int user : users) {
+ // TODO(multiArch): Fix this so that it links to the
+ // correct directory. We're currently pointing to root. but we
+ // must point to the arch specific subdirectory (if applicable).
+ //
+ // TODO(multiArch): Bogus reference to nativeLibraryDir.
if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
- newNativePath, user) < 0) {
+ newNativeRoot, user) < 0) {
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
}
}
@@ -12801,15 +12976,21 @@
pkg.applicationInfo.setResourcePath(newResPath);
pkg.applicationInfo.setBaseResourcePath(newResPath);
pkg.applicationInfo.setSplitResourcePaths(null);
- pkg.applicationInfo.nativeLibraryDir = newNativePath;
+ // Null out the legacy nativeLibraryDir so that we stop using it and
+ // always derive the codepath.
+ pkg.applicationInfo.legacyNativeLibraryDir = null;
PackageSetting ps = (PackageSetting) pkg.mExtras;
ps.codePath = new File(pkg.applicationInfo.getCodePath());
ps.codePathString = ps.codePath.getPath();
- ps.resourcePath = new File(
- pkg.applicationInfo.getResourcePath());
+ ps.resourcePath = new File(pkg.applicationInfo.getResourcePath());
ps.resourcePathString = ps.resourcePath.getPath();
- ps.nativeLibraryPathString = newNativePath;
+
+ // Note that we don't have to recalculate the primary and secondary
+ // CPU ABIs because they must already have been calculated during the
+ // initial install of the app.
+ ps.legacyNativeLibraryPathString = null;
+
// Set the application info flag
// correctly.
if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 284da99..a6571cf 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -30,9 +30,10 @@
SharedUserSetting sharedUser;
PackageSetting(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, String cpuAbiString, int pVersionCode, int pkgFlags) {
- super(name, realName, codePath, resourcePath, nativeLibraryPathString, cpuAbiString, pVersionCode,
- pkgFlags);
+ String legacyNativeLibraryPathString, String primaryCpuAbiString,
+ String secondaryCpuAbiString, int pVersionCode, int pkgFlags) {
+ super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
+ primaryCpuAbiString, secondaryCpuAbiString, pVersionCode, pkgFlags);
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index f263e07..3390efe 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -55,8 +55,16 @@
String codePathString;
File resourcePath;
String resourcePathString;
- String nativeLibraryPathString;
- String cpuAbiString;
+
+ /**
+ * The path under which native libraries for legacy apps are unpacked.
+ * Will be set to {@code null} for newer installs, where the path can be
+ * derived from {@link #codePath} unambiguously.
+ */
+ String legacyNativeLibraryPathString;
+
+ String primaryCpuAbiString;
+ String secondaryCpuAbiString;
long timeStamp;
long firstInstallTime;
long lastUpdateTime;
@@ -84,11 +92,13 @@
/* package name of the app that installed this package */
String installerPackageName;
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, String cpuAbiString, int pVersionCode, int pkgFlags) {
+ String legacyNativeLibraryPathString, String primaryCpuAbiString,
+ String secondaryCpuAbiString, int pVersionCode, int pkgFlags) {
super(pkgFlags);
this.name = name;
this.realName = realName;
- init(codePath, resourcePath, nativeLibraryPathString, cpuAbiString, pVersionCode);
+ init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
+ secondaryCpuAbiString, pVersionCode);
}
/**
@@ -104,8 +114,9 @@
codePathString = base.codePathString;
resourcePath = base.resourcePath;
resourcePathString = base.resourcePathString;
- nativeLibraryPathString = base.nativeLibraryPathString;
- cpuAbiString = base.cpuAbiString;
+ legacyNativeLibraryPathString = base.legacyNativeLibraryPathString;
+ primaryCpuAbiString = base.primaryCpuAbiString;
+ secondaryCpuAbiString = base.secondaryCpuAbiString;
timeStamp = base.timeStamp;
firstInstallTime = base.firstInstallTime;
lastUpdateTime = base.lastUpdateTime;
@@ -132,14 +143,15 @@
}
- void init(File codePath, File resourcePath, String nativeLibraryPathString,
- String requiredCpuAbiString, int pVersionCode) {
+ void init(File codePath, File resourcePath, String legacyNativeLibraryPathString,
+ String primaryCpuAbiString, String secondaryCpuAbiString, int pVersionCode) {
this.codePath = codePath;
this.codePathString = codePath.toString();
this.resourcePath = resourcePath;
this.resourcePathString = resourcePath.toString();
- this.nativeLibraryPathString = nativeLibraryPathString;
- this.cpuAbiString = requiredCpuAbiString;
+ this.legacyNativeLibraryPathString = legacyNativeLibraryPathString;
+ this.primaryCpuAbiString = primaryCpuAbiString;
+ this.secondaryCpuAbiString = secondaryCpuAbiString;
this.versionCode = pVersionCode;
}
@@ -170,7 +182,8 @@
grantedPermissions = base.grantedPermissions;
gids = base.gids;
- cpuAbiString = base.cpuAbiString;
+ primaryCpuAbiString = base.primaryCpuAbiString;
+ secondaryCpuAbiString = base.secondaryCpuAbiString;
timeStamp = base.timeStamp;
firstInstallTime = base.firstInstallTime;
lastUpdateTime = base.lastUpdateTime;
diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
index 36c3a34..85be651 100644
--- a/services/core/java/com/android/server/pm/PendingPackage.java
+++ b/services/core/java/com/android/server/pm/PendingPackage.java
@@ -22,9 +22,10 @@
final int sharedId;
PendingPackage(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, String requiredCpuAbiString, int sharedId, int pVersionCode, int pkgFlags) {
- super(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode,
- pkgFlags);
+ String nativeLibrary32PathString, String nativeLibrary64PathString,
+ String requiredCpuAbiString, int sharedId, int pVersionCode, int pkgFlags) {
+ super(name, realName, codePath, resourcePath, nativeLibrary32PathString, nativeLibrary64PathString,
+ requiredCpuAbiString, pVersionCode, pkgFlags);
this.sharedId = sharedId;
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 81ea72c..71b8974 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -29,7 +29,13 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
import android.os.PatternMatcher;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.LogPrinter;
import com.android.internal.util.FastXmlSerializer;
@@ -56,12 +62,6 @@
import android.content.pm.UserInfo;
import android.content.pm.PackageUserState;
import android.content.pm.VerifierDeviceIdentity;
-import android.os.Binder;
-import android.os.Environment;
-import android.os.FileUtils;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -317,11 +317,12 @@
PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, String cpuAbiString, int pkgFlags, UserHandle user, boolean add) {
+ String nativeLibraryRoot, String primaryCpuAbi, String secondaryCpuAbi, int pkgFlags,
+ UserHandle user, boolean add) {
final String name = pkg.packageName;
PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
- resourcePath, nativeLibraryPathString, cpuAbiString, pkg.mVersionCode, pkgFlags,
- user, add, true /* allowInstall */);
+ resourcePath, nativeLibraryRoot, primaryCpuAbi, secondaryCpuAbi,
+ pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);
return p;
}
@@ -407,7 +408,8 @@
p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
- p.nativeLibraryPathString, p.cpuAbiString, p.appId, p.versionCode, p.pkgFlags);
+ p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
+ p.secondaryCpuAbiString, p.appId, p.versionCode, p.pkgFlags);
mDisabledSysPackages.remove(name);
return ret;
}
@@ -421,7 +423,8 @@
}
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, String cpuAbiString, int uid, int vc, int pkgFlags) {
+ String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
+ int uid, int vc, int pkgFlags) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -431,8 +434,8 @@
"Adding duplicate package, keeping first: " + name);
return null;
}
- p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, cpuAbiString,
- vc, pkgFlags);
+ p = new PackageSetting(name, realName, codePath, resourcePath,
+ legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, vc, pkgFlags);
p.appId = uid;
if (addUserIdLPw(uid, p, name)) {
mPackages.put(name, p);
@@ -500,11 +503,12 @@
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, String cpuAbiString, int vc, int pkgFlags,
- UserHandle installUser, boolean add, boolean allowInstall) {
+ String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
+ int vc, int pkgFlags, UserHandle installUser, boolean add, boolean allowInstall) {
PackageSetting p = mPackages.get(name);
if (p != null) {
- p.cpuAbiString = cpuAbiString;
+ p.primaryCpuAbiString = primaryCpuAbiString;
+ p.secondaryCpuAbiString = secondaryCpuAbiString;
if (!p.codePath.equals(codePath)) {
// Check to see if its a disabled system app
if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
@@ -524,7 +528,7 @@
* package settings since we might have moved from
* internal to external storage or vice versa.
*/
- p.nativeLibraryPathString = nativeLibraryPathString;
+ p.legacyNativeLibraryPathString = legacyNativeLibraryPathString;
}
}
if (p.sharedUser != sharedUser) {
@@ -548,7 +552,7 @@
if (origPackage != null) {
// We are consuming the data from an existing package.
p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
- nativeLibraryPathString, cpuAbiString, vc, pkgFlags);
+ legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, vc, pkgFlags);
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ name + " is adopting original package " + origPackage.name);
// Note that we will retain the new package's signature so
@@ -565,7 +569,7 @@
p.setTimeStamp(codePath.lastModified());
} else {
p = new PackageSetting(name, realName, codePath, resourcePath,
- nativeLibraryPathString, cpuAbiString, vc, pkgFlags);
+ legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, vc, pkgFlags);
p.setTimeStamp(codePath.lastModified());
p.sharedUser = sharedUser;
// If this is not a system app, it starts out stopped.
@@ -699,14 +703,15 @@
p.resourcePath = new File(resourcePath);
p.resourcePathString = resourcePath;
}
- // Update the native library path if needed
- final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir;
- if (nativeLibraryPath != null
- && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) {
- p.nativeLibraryPathString = nativeLibraryPath;
+ // Update the native library paths if needed
+ final String nativeLibraryRoot = pkg.applicationInfo.legacyNativeLibraryDir;
+ if (nativeLibraryRoot != null && !nativeLibraryRoot.equalsIgnoreCase(p.legacyNativeLibraryPathString)) {
+ p.legacyNativeLibraryPathString = nativeLibraryRoot;
}
+
// Update the required Cpu Abi
- p.cpuAbiString = pkg.applicationInfo.cpuAbi;
+ p.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
+ p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
// Update version code if needed
if (pkg.mVersionCode != p.versionCode) {
p.versionCode = pkg.mVersionCode;
@@ -1861,12 +1866,16 @@
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
}
- if (pkg.nativeLibraryPathString != null) {
- serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+ if (pkg.legacyNativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
}
- if (pkg.cpuAbiString != null) {
- serializer.attribute(null, "requiredCpuAbi", pkg.cpuAbiString);
+ if (pkg.primaryCpuAbiString != null) {
+ serializer.attribute(null, "primaryCpuAbi", pkg.primaryCpuAbiString);
}
+ if (pkg.secondaryCpuAbiString != null) {
+ serializer.attribute(null, "secondaryCpuAbi", pkg.secondaryCpuAbiString);
+ }
+
if (pkg.sharedUser == null) {
serializer.attribute(null, "userId", Integer.toString(pkg.appId));
} else {
@@ -1906,12 +1915,17 @@
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
}
- if (pkg.nativeLibraryPathString != null) {
- serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+
+ if (pkg.legacyNativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
}
- if (pkg.cpuAbiString != null) {
- serializer.attribute(null, "requiredCpuAbi", pkg.cpuAbiString);
+ if (pkg.primaryCpuAbiString != null) {
+ serializer.attribute(null, "primaryCpuAbi", pkg.primaryCpuAbiString);
}
+ if (pkg.secondaryCpuAbiString != null) {
+ serializer.attribute(null, "secondaryCpuAbi", pkg.secondaryCpuAbiString);
+ }
+
serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
@@ -2219,7 +2233,8 @@
if (idObj != null && idObj instanceof SharedUserSetting) {
PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
- pp.nativeLibraryPathString, pp.cpuAbiString, pp.versionCode, pp.pkgFlags,
+ pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString,
+ pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags,
null, true /* add */, false /* allowInstall */);
if (p == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -2638,8 +2653,16 @@
String realName = parser.getAttributeValue(null, "realName");
String codePathStr = parser.getAttributeValue(null, "codePath");
String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- String cpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+
+ String legacyCpuAbiStr = parser.getAttributeValue(null, "requiredCpuAbi");
+ String legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+
+ String primaryCpuAbiStr = parser.getAttributeValue(null, "primaryCpuAbi");
+ String secondaryCpuAbiStr = parser.getAttributeValue(null, "secondaryCpuAbi");
+
+ if (primaryCpuAbiStr == null && legacyCpuAbiStr != null) {
+ primaryCpuAbiStr = legacyCpuAbiStr;
+ }
if (resourcePathStr == null) {
resourcePathStr = codePathStr;
@@ -2660,7 +2683,8 @@
pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
}
PackageSetting ps = new PackageSetting(name, realName, codePathFile,
- new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, versionCode, pkgFlags);
+ new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
+ secondaryCpuAbiStr, versionCode, pkgFlags);
String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
@@ -2726,8 +2750,10 @@
String sharedIdStr = null;
String codePathStr = null;
String resourcePathStr = null;
- String nativeLibraryPathStr = null;
- String cpuAbiString = null;
+ String legacyCpuAbiString = null;
+ String legacyNativeLibraryPathStr = null;
+ String primaryCpuAbiString = null;
+ String secondaryCpuAbiString = null;
String systemStr = null;
String installerPackageName = null;
String uidError = null;
@@ -2746,9 +2772,17 @@
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
codePathStr = parser.getAttributeValue(null, "codePath");
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- cpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+ legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+
+ legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+ primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi");
+ secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi");
+
+ if (primaryCpuAbiString == null && legacyCpuAbiString != null) {
+ primaryCpuAbiString = legacyCpuAbiString;
+ }
+;
version = parser.getAttributeValue(null, "version");
if (version != null) {
try {
@@ -2825,8 +2859,8 @@
+ parser.getPositionDescription());
} else if (userId > 0) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
- new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, userId, versionCode,
- pkgFlags);
+ new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
+ secondaryCpuAbiString, userId, versionCode, pkgFlags);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ userId + " pkg=" + packageSetting);
@@ -2843,8 +2877,8 @@
userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
if (userId > 0) {
packageSetting = new PendingPackage(name.intern(), realName, new File(
- codePathStr), new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, userId,
- versionCode, pkgFlags);
+ codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
+ primaryCpuAbiString, legacyCpuAbiString, userId, versionCode, pkgFlags);
packageSetting.setTimeStamp(timeStamp);
packageSetting.firstInstallTime = firstInstallTime;
packageSetting.lastUpdateTime = lastUpdateTime;
@@ -2871,8 +2905,9 @@
if (packageSetting != null) {
packageSetting.uidError = "true".equals(uidError);
packageSetting.installerPackageName = installerPackageName;
- packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
- packageSetting.cpuAbiString = cpuAbiString;
+ packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
+ packageSetting.primaryCpuAbiString = primaryCpuAbiString;
+ packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
// Handle legacy string here for single-user mode
final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
if (enabledStr != null) {
@@ -3417,8 +3452,9 @@
pw.print(prefix); pw.print(" pkg="); pw.println(ps.pkg);
pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString);
pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
- pw.print(prefix); pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
- pw.print(prefix); pw.print(" requiredCpuAbi="); pw.println(ps.cpuAbiString);
+ pw.print(prefix); pw.print(" legacyNativeLibraryDir="); pw.println(ps.legacyNativeLibraryPathString);
+ pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
+ pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
if (ps.pkg != null) {
pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);