summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/content/pm/PackageInstaller.java12
-rw-r--r--core/java/android/content/pm/PackageParser.java42
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java198
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java50
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java246
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java32
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java36
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java285
9 files changed, 475 insertions, 428 deletions
diff --git a/api/current.txt b/api/current.txt
index 8f75785..e995fc9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8667,7 +8667,7 @@ package android.content.pm {
method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void uninstall(java.lang.String, android.content.IntentSender);
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
- field public static final java.lang.String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 4ac701f..7419ebc 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -105,10 +105,14 @@ public class PackageInstaller {
public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
/**
- * List of package names that are relevant to a status.
+ * Package name relevant to a status.
*
- * @see Intent#getStringArrayExtra(String)
+ * @see Intent#getStringExtra(String)
*/
+ public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+
+ /** {@hide} */
+ @Deprecated
public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
/** {@hide} */
@@ -178,8 +182,8 @@ public class PackageInstaller {
* permission, incompatible certificates, etc. The user may be able to
* uninstall another app to fix the issue.
* <p>
- * The result may also contain {@link #EXTRA_PACKAGE_NAMES} with the
- * specific packages identified as the cause of the conflict.
+ * The result may also contain {@link #EXTRA_PACKAGE_NAME} with the
+ * specific package identified as the cause of the conflict.
*
* @see #EXTRA_STATUS_MESSAGE
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2c50f25..eb8b762 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -596,7 +596,7 @@ public class PackageParser {
public final static int PARSE_ON_SDCARD = 1<<5;
public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
public final static int PARSE_IS_PRIVILEGED = 1<<7;
- public final static int PARSE_GET_SIGNATURES = 1<<8;
+ public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
@@ -1087,34 +1087,6 @@ public class PackageParser {
}
}
- /**
- * Only collect certificates on the manifest; does not validate signatures
- * across remainder of package.
- */
- private static Signature[] collectManifestCertificates(File apkFile)
- throws PackageParserException {
- final String apkPath = apkFile.getAbsolutePath();
- try {
- final StrictJarFile jarFile = new StrictJarFile(apkPath);
- try {
- final ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
- if (jarEntry == null) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Package " + apkPath + " has no manifest");
- }
-
- final Certificate[][] certs = loadCertificates(jarFile, jarEntry);
- return convertToSignatures(certs);
-
- } finally {
- jarFile.close();
- }
- } catch (GeneralSecurityException | IOException | RuntimeException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
- "Failed to collect certificates from " + apkPath, e);
- }
- }
-
private static Signature[] convertToSignatures(Certificate[][] certs)
throws CertificateEncodingException {
final Signature[] res = new Signature[certs.length];
@@ -1129,7 +1101,8 @@ public class PackageParser {
* file, including package name, split name, and install location.
*
* @param apkFile path to a single APK
- * @param flags optional parse flags, such as {@link #PARSE_GET_SIGNATURES}
+ * @param flags optional parse flags, such as
+ * {@link #PARSE_COLLECT_CERTIFICATES}
*/
public static ApkLite parseApkLite(File apkFile, int flags)
throws PackageParserException {
@@ -1154,11 +1127,12 @@ public class PackageParser {
final Resources res = new Resources(assets, metrics, null);
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
- // Only collect certificates on the manifest; does not validate
- // signatures across remainder of package.
final Signature[] signatures;
- if ((flags & PARSE_GET_SIGNATURES) != 0) {
- signatures = collectManifestCertificates(apkFile);
+ if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
+ // TODO: factor signature related items out of Package object
+ final Package tempPkg = new Package(null);
+ collectCertificates(tempPkg, apkFile, 0);
+ signatures = tempPkg.mSignatures;
} else {
signatures = null;
}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index d76d0d4..179d5e8 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -19,15 +19,25 @@ package com.android.internal.content;
import static android.content.pm.PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.NO_NATIVE_LIBRARIES;
+import static android.system.OsConstants.S_IRGRP;
+import static android.system.OsConstants.S_IROTH;
+import static android.system.OsConstants.S_IRWXU;
+import static android.system.OsConstants.S_IXGRP;
+import static android.system.OsConstants.S_IXOTH;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.Package;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
+import android.os.Build;
+import android.os.SELinux;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Slog;
import dalvik.system.CloseGuard;
+import dalvik.system.VMRuntime;
import java.io.Closeable;
import java.io.File;
@@ -44,6 +54,10 @@ public class NativeLibraryHelper {
private static final boolean DEBUG_NATIVE = false;
+ // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate
+ // that the cpuAbiOverride must be clear.
+ public static final String CLEAR_ABI_OVERRIDE = "-";
+
/**
* A handle to an opened package, consisting of one or more APKs. Used as
* input to the various NativeLibraryHelper methods. Allows us to scan and
@@ -126,27 +140,17 @@ public class NativeLibraryHelper {
private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
- /**
- * Sums the size of native binaries in an APK for a given ABI.
- *
- * @return size of all native binary files in bytes
- */
- public static long sumNativeBinariesLI(Handle handle, String[] abis) {
+ private native static int nativeCopyNativeBinaries(long handle,
+ String sharedLibraryPath, String abiToCopy);
+
+ private static long sumNativeBinaries(Handle handle, String abi) {
long sum = 0;
for (long apkHandle : handle.apkHandles) {
- // 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);
- }
+ sum += nativeSumNativeBinaries(apkHandle, abi);
}
return sum;
}
- private native static int nativeCopyNativeBinaries(long handle,
- String sharedLibraryPath, String abiToCopy);
-
/**
* Copies native binaries to a shared library directory.
*
@@ -244,9 +248,171 @@ public class NativeLibraryHelper {
}
}
+ 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 long sumNativeBinaries(Handle handle, String[] abiList) {
+ int abi = findSupportedAbi(handle, abiList);
+ if (abi >= 0) {
+ return sumNativeBinaries(handle, abiList[abi]);
+ } else {
+ return 0;
+ }
+ }
+
+ public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot,
+ String[] abiList, boolean useIsaSubdir) throws IOException {
+ createNativeLibrarySubdir(libraryRoot);
+
+ /*
+ * If this is an internal application or our nativeLibraryPath points to
+ * the app-lib directory, unpack the libraries if necessary.
+ */
+ int abi = 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(libraryRoot, instructionSet);
+ createNativeLibrarySubdir(isaSubdir);
+ subDir = isaSubdir;
+ } else {
+ subDir = libraryRoot;
+ }
+
+ int copyRet = copyNativeBinariesIfNeededLI(handle, subDir, abiList[abi]);
+ if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
+ return copyRet;
+ }
+ }
+
+ return abi;
+ }
+
+ public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot,
+ String abiOverride, boolean multiArch) {
+ try {
+ 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 && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
+ Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
+ }
+
+ int copyRet = PackageManager.NO_NATIVE_LIBRARIES;
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot,
+ Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */);
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
+ copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+ Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet);
+ return copyRet;
+ }
+ }
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot,
+ Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */);
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
+ copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+ Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet);
+ return copyRet;
+ }
+ }
+ } else {
+ String cpuAbiOverride = null;
+ if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
+ cpuAbiOverride = null;
+ } else if (abiOverride != null) {
+ cpuAbiOverride = abiOverride;
+ }
+
+ String[] abiList = (cpuAbiOverride != null) ?
+ new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
+ hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
+ }
+
+ int copyRet = copyNativeBinariesIfNeededLI(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;
+ }
+ }
+
+ return PackageManager.INSTALL_SUCCEEDED;
+ } catch (IOException e) {
+ Slog.e(TAG, "Copying native libraries failed", e);
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+ }
+
+ public static long sumNativeBinaries(Handle handle, String abiOverride, boolean multiArch)
+ throws IOException {
+ long sum = 0;
+ 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 && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
+ Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
+ }
+
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ sum += sumNativeBinaries(handle, Build.SUPPORTED_32_BIT_ABIS);
+ }
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ sum += sumNativeBinaries(handle, Build.SUPPORTED_64_BIT_ABIS);
+ }
+ } else {
+ String cpuAbiOverride = null;
+ if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
+ cpuAbiOverride = null;
+ } else if (abiOverride != null) {
+ cpuAbiOverride = abiOverride;
+ }
+
+ String[] abiList = (cpuAbiOverride != null) ?
+ new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
+ hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
+ }
+
+ sum += sumNativeBinaries(handle, abiList);
+ }
+ return sum;
+ }
+
// We don't care about the other return values for now.
private static final int BITCODE_PRESENT = 1;
+ private static native int hasRenderscriptBitcode(long apkHandle);
+
public static boolean hasRenderscriptBitcode(Handle handle) throws IOException {
for (long apkHandle : handle.apkHandles) {
final int res = hasRenderscriptBitcode(apkHandle);
@@ -258,6 +424,4 @@ public class NativeLibraryHelper {
}
return false;
}
-
- private static native int hasRenderscriptBitcode(long apkHandle);
}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index fd96f64..a529cc3 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -17,13 +17,17 @@
package com.android.internal.content;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
+import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
@@ -215,7 +219,7 @@ public class PackageHelper {
/**
* Extract public files for the single given APK.
*/
- public static int extractPublicFiles(String apkPath, File publicZipFile)
+ public static long extractPublicFiles(File apkFile, File publicZipFile)
throws IOException {
final FileOutputStream fstr;
final ZipOutputStream publicZipOutStream;
@@ -226,12 +230,13 @@ public class PackageHelper {
} else {
fstr = new FileOutputStream(publicZipFile);
publicZipOutStream = new ZipOutputStream(fstr);
+ Log.d(TAG, "Extracting " + apkFile + " to " + publicZipFile);
}
- int size = 0;
+ long size = 0L;
try {
- final ZipFile privateZip = new ZipFile(apkPath);
+ final ZipFile privateZip = new ZipFile(apkFile.getAbsolutePath());
try {
// Copy manifest, resources.arsc and res directory to public zip
for (final ZipEntry zipEntry : Collections.list(privateZip.entries())) {
@@ -308,8 +313,15 @@ public class PackageHelper {
* Given a requested {@link PackageInfo#installLocation} and calculated
* install size, pick the actual location to install the app.
*/
- public static int resolveInstallLocation(Context context, int installLocation, long sizeBytes,
- int installFlags) {
+ public static int resolveInstallLocation(Context context, String packageName,
+ int installLocation, long sizeBytes, int installFlags) {
+ ApplicationInfo existingInfo = null;
+ try {
+ existingInfo = context.getPackageManager().getApplicationInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException ignored) {
+ }
+
final int prefer;
final boolean checkBoth;
if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
@@ -325,7 +337,16 @@ public class PackageHelper {
prefer = RECOMMEND_INSTALL_EXTERNAL;
checkBoth = true;
} else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
- prefer = RECOMMEND_INSTALL_INTERNAL;
+ // When app is already installed, prefer same medium
+ if (existingInfo != null) {
+ if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ prefer = RECOMMEND_INSTALL_EXTERNAL;
+ } else {
+ prefer = RECOMMEND_INSTALL_INTERNAL;
+ }
+ } else {
+ prefer = RECOMMEND_INSTALL_INTERNAL;
+ }
checkBoth = true;
} else {
prefer = RECOMMEND_INSTALL_INTERNAL;
@@ -337,14 +358,15 @@ public class PackageHelper {
boolean fitsOnInternal = false;
if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
- fitsOnInternal = (sizeBytes
- <= storage.getStorageBytesUntilLow(Environment.getDataDirectory()));
+ final File target = Environment.getDataDirectory();
+ fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
}
boolean fitsOnExternal = false;
if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) {
- fitsOnExternal = (sizeBytes
- <= storage.getStorageBytesUntilLow(Environment.getExternalStorageDirectory()));
+ final File target = new UserEnvironment(UserHandle.USER_OWNER)
+ .getExternalStorageDirectory();
+ fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
}
if (prefer == RECOMMEND_INSTALL_INTERNAL) {
@@ -377,4 +399,12 @@ public class PackageHelper {
return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
+
+ public static String replaceEnd(String str, String before, String after) {
+ if (!str.endsWith(before)) {
+ throw new IllegalArgumentException(
+ "Expected " + str + " to end with " + before);
+ }
+ return str.substring(0, str.length() - before.length()) + after;
+ }
}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 4c225c1..fae30e5 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -30,7 +30,6 @@ import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.res.ObbInfo;
import android.content.res.ObbScanner;
-import android.os.Build;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
@@ -67,7 +66,6 @@ import java.io.OutputStream;
*/
public class DefaultContainerService extends IntentService {
private static final String TAG = "DefContainer";
- private static final boolean localLOGV = false;
private static final String LIB_DIR_NAME = "lib";
@@ -112,7 +110,7 @@ public class DefaultContainerService extends IntentService {
return copyPackageToContainerInner(pkg, handle, containerId, key, isExternal,
isForwardLocked, abiOverride);
} catch (PackageParserException | IOException e) {
- Slog.w(TAG, "Failed to parse package at " + packagePath);
+ Slog.w(TAG, "Failed to copy package at " + packagePath, e);
return null;
} finally {
IoUtils.closeQuietly(handle);
@@ -188,7 +186,7 @@ public class DefaultContainerService extends IntentService {
ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers;
ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
- pkg.installLocation, sizeBytes, flags);
+ pkg.packageName, pkg.installLocation, sizeBytes, flags);
ret.multiArch = pkg.multiArch;
return ret;
@@ -313,161 +311,73 @@ public class DefaultContainerService extends IntentService {
private String copyPackageToContainerInner(PackageLite pkg, NativeLibraryHelper.Handle handle,
String newCid, String key, boolean isExternal, boolean isForwardLocked,
- String abiOverride) {
- // TODO: extend to support copying all split APKs
- if (!ArrayUtils.isEmpty(pkg.splitNames)) {
- throw new UnsupportedOperationException("Copying split APKs not yet supported");
- }
-
- final String resFileName = "pkg.apk";
- final String publicResFileName = "res.zip";
-
- if (pkg.multiArch) {
- // TODO: Support multiArch installs on ASEC.
- throw new IllegalArgumentException("multiArch not supported on ASEC installs.");
- }
+ String abiOverride) throws IOException {
- // 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. Round up to
- // nearest MB, and tack on an extra MB for filesystem overhead.
- final int sizeMb;
- try {
- final long sizeBytes = calculateInstalledSizeInner(pkg, handle, isForwardLocked, abis);
- sizeMb = ((int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES)) + 1;
- } catch (IOException e) {
- Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath());
- return null;
- }
+ // Calculate container size, rounding up to nearest MB and adding an
+ // extra MB for filesystem overhead
+ final long sizeBytes = calculateInstalledSizeInner(pkg, handle, isForwardLocked,
+ abiOverride);
+ final int sizeMb = ((int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES)) + 1;
// Create new container
- final String newCachePath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid(),
+ final String newMountPath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid(),
isExternal);
- if (newCachePath == null) {
- Slog.e(TAG, "Failed to create container " + newCid);
- return null;
- }
-
- if (localLOGV) {
- Slog.i(TAG, "Created container for " + newCid + " at path : " + newCachePath);
- }
-
- final File resFile = new File(newCachePath, resFileName);
- if (FileUtils.copyFile(new File(codePath), resFile)) {
- if (localLOGV) {
- Slog.i(TAG, "Copied " + codePath + " to " + resFile);
- }
- } else {
- Slog.e(TAG, "Failed to copy " + codePath + " to " + resFile);
- // Clean up container
- PackageHelper.destroySdDir(newCid);
- return null;
+ if (newMountPath == null) {
+ throw new IOException("Failed to create container " + newCid);
}
+ final File targetDir = new File(newMountPath);
try {
- Os.chmod(resFile.getAbsolutePath(), 0640);
- } catch (ErrnoException e) {
- Slog.e(TAG, "Could not chown APK: " + e.getMessage());
- PackageHelper.destroySdDir(newCid);
- return null;
- }
-
- if (isForwardLocked) {
- File publicZipFile = new File(newCachePath, publicResFileName);
- try {
- PackageHelper.extractPublicFiles(resFile.getAbsolutePath(), publicZipFile);
- if (localLOGV) {
- Slog.i(TAG, "Copied resources to " + publicZipFile);
+ // Copy all APKs
+ copyFile(pkg.baseCodePath, targetDir, "base.apk", isForwardLocked);
+ if (!ArrayUtils.isEmpty(pkg.splitNames)) {
+ for (int i = 0; i < pkg.splitNames.length; i++) {
+ copyFile(pkg.splitCodePaths[i], targetDir,
+ "split_" + pkg.splitNames[i] + ".apk", isForwardLocked);
}
- } catch (IOException e) {
- Slog.e(TAG, "Could not chown public APK " + publicZipFile.getAbsolutePath() + ": "
- + e.getMessage());
- PackageHelper.destroySdDir(newCid);
- return null;
}
- try {
- Os.chmod(publicZipFile.getAbsolutePath(), 0644);
- } catch (ErrnoException e) {
- Slog.e(TAG, "Could not chown public resource file: " + e.getMessage());
- PackageHelper.destroySdDir(newCid);
- return null;
+ // Extract native code
+ final File libraryRoot = new File(targetDir, LIB_DIR_NAME);
+ final int res = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, libraryRoot,
+ abiOverride, pkg.multiArch);
+ if (res != PackageManager.INSTALL_SUCCEEDED) {
+ throw new IOException("Failed to extract native code, res=" + res);
}
- }
- final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
- if (sharedLibraryDir.mkdir()) {
- int ret = PackageManager.INSTALL_SUCCEEDED;
- 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, abi);
-
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath());
- PackageHelper.destroySdDir(newCid);
- return null;
- }
+ if (!PackageHelper.finalizeSdDir(newCid)) {
+ throw new IOException("Failed to finalize " + newCid);
}
- } else {
- Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath());
- PackageHelper.destroySdDir(newCid);
- return null;
- }
- if (!PackageHelper.finalizeSdDir(newCid)) {
- Slog.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath);
- // Clean up container
- PackageHelper.destroySdDir(newCid);
- return null;
- }
-
- if (localLOGV) {
- Slog.i(TAG, "Finalized container " + newCid);
- }
-
- if (PackageHelper.isContainerMounted(newCid)) {
- if (localLOGV) {
- Slog.i(TAG, "Unmounting " + newCid + " at path " + newCachePath);
+ if (PackageHelper.isContainerMounted(newCid)) {
+ PackageHelper.unMountSdDir(newCid);
}
- // Force a gc to avoid being killed.
- Runtime.getRuntime().gc();
- PackageHelper.unMountSdDir(newCid);
- } else {
- if (localLOGV) {
- Slog.i(TAG, "Container " + newCid + " not mounted");
- }
+ } catch (ErrnoException e) {
+ PackageHelper.destroySdDir(newCid);
+ throw e.rethrowAsIOException();
+ } catch (IOException e) {
+ PackageHelper.destroySdDir(newCid);
+ throw e;
}
- return newCachePath;
+ return newMountPath;
}
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
throws IOException, RemoteException {
- copyFile(pkg.baseCodePath, "base.apk", target);
+ copyFile(pkg.baseCodePath, target, "base.apk");
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
for (int i = 0; i < pkg.splitNames.length; i++) {
- copyFile(pkg.splitCodePaths[i], "split_" + pkg.splitNames[i] + ".apk", target);
+ copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");
}
}
return PackageManager.INSTALL_SUCCEEDED;
}
- private void copyFile(String sourcePath, String targetName,
- IParcelFileDescriptorFactory target) throws IOException, RemoteException {
+ private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)
+ throws IOException, RemoteException {
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
InputStream in = null;
OutputStream out = null;
@@ -482,76 +392,58 @@ public class DefaultContainerService extends IntentService {
}
}
+ private void copyFile(String sourcePath, File targetDir, String targetName,
+ boolean isForwardLocked) throws IOException, ErrnoException {
+ final File sourceFile = new File(sourcePath);
+ final File targetFile = new File(targetDir, targetName);
+
+ Slog.d(TAG, "Copying " + sourceFile + " to " + targetFile);
+ if (!FileUtils.copyFile(sourceFile, targetFile)) {
+ throw new IOException("Failed to copy " + sourceFile + " to " + targetFile);
+ }
+
+ if (isForwardLocked) {
+ final String publicTargetName = PackageHelper.replaceEnd(targetName,
+ ".apk", ".zip");
+ final File publicTargetFile = new File(targetDir, publicTargetName);
+
+ PackageHelper.extractPublicFiles(sourceFile, publicTargetFile);
+
+ Os.chmod(targetFile.getAbsolutePath(), 0640);
+ Os.chmod(publicTargetFile.getAbsolutePath(), 0644);
+ } else {
+ Os.chmod(targetFile.getAbsolutePath(), 0644);
+ }
+ }
+
private long calculateInstalledSizeInner(PackageLite pkg, boolean isForwardLocked,
String abiOverride) throws IOException {
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(pkg);
- return calculateInstalledSizeInner(pkg, handle, isForwardLocked,
- calculateAbiList(handle, abiOverride, pkg.multiArch));
+ return calculateInstalledSizeInner(pkg, handle, isForwardLocked, abiOverride);
} finally {
IoUtils.closeQuietly(handle);
}
}
private long calculateInstalledSizeInner(PackageLite pkg, NativeLibraryHelper.Handle handle,
- boolean isForwardLocked, String[] abis) throws IOException {
+ boolean isForwardLocked, String abiOverride) throws IOException {
long sizeBytes = 0;
// Include raw APKs, and possibly unpacked resources
for (String codePath : pkg.getAllCodePaths()) {
- sizeBytes += new File(codePath).length();
+ final File codeFile = new File(codePath);
+ sizeBytes += codeFile.length();
if (isForwardLocked) {
- sizeBytes += PackageHelper.extractPublicFiles(codePath, null);
+ sizeBytes += PackageHelper.extractPublicFiles(codeFile, null);
}
}
// Include all relevant native code
- if (!ArrayUtils.isEmpty(abis)) {
- sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, abis);
- }
+ sizeBytes += NativeLibraryHelper.sumNativeBinaries(handle, abiOverride, pkg.multiArch);
return sizeBytes;
}
-
- 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;
- }
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0393518..03cb2e9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -56,6 +56,7 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
@@ -485,7 +486,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
// Brand new install, use best resolved location. This also verifies
// that target has enough free space for the install.
final int resolved = PackageHelper.resolveInstallLocation(mContext,
- params.installLocation, params.sizeBytes, params.installFlags);
+ params.appPackageName, params.installLocation, params.sizeBytes,
+ params.installFlags);
if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
stageInternal = true;
} else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
@@ -568,7 +570,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private void checkExternalStorage(long sizeBytes) throws IOException {
if (sizeBytes <= 0) return;
- final File target = Environment.getExternalStorageDirectory();
+ final File target = new UserEnvironment(UserHandle.USER_OWNER)
+ .getExternalStorageDirectory();
final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target);
if (target.getUsableSpace() < targetBytes) {
@@ -696,7 +699,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");
final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
- statusReceiver);
+ statusReceiver, packageName);
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
== PackageManager.PERMISSION_GRANTED) {
// Sweet, call straight through!
@@ -773,15 +776,19 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
private final Context mContext;
private final IntentSender mTarget;
+ private final String mPackageName;
- public PackageDeleteObserverAdapter(Context context, IntentSender target) {
+ public PackageDeleteObserverAdapter(Context context, IntentSender target,
+ String packageName) {
mContext = context;
mTarget = target;
+ mPackageName = packageName;
}
@Override
public void onUserActionRequired(Intent intent) {
final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_PENDING_USER_ACTION);
fillIn.putExtra(Intent.EXTRA_INTENT, intent);
@@ -794,6 +801,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
@Override
public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageManager.deleteStatusToPublicStatus(returnCode));
fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
@@ -809,15 +817,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
static class PackageInstallObserverAdapter extends PackageInstallObserver {
private final Context mContext;
private final IntentSender mTarget;
+ private final int mSessionId;
- public PackageInstallObserverAdapter(Context context, IntentSender target) {
+ public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId) {
mContext = context;
mTarget = target;
+ mSessionId = sessionId;
}
@Override
public void onUserActionRequired(Intent intent) {
final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_PENDING_USER_ACTION);
fillIn.putExtra(Intent.EXTRA_INTENT, intent);
@@ -831,6 +842,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageManager.installStatusToPublicStatus(returnCode));
fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
@@ -840,8 +852,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
final String existing = extras.getString(
PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
if (!TextUtils.isEmpty(existing)) {
- fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAMES, new String[] {
- existing });
+ fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, existing);
}
}
try {
@@ -986,5 +997,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
writeSessionsAsync();
}
+
+ public void onSessionSealed(PackageInstallerSession session) {
+ // It's very important that we block until we've recorded the
+ // session as being sealed, since we never want to allow mutation
+ // after sealing.
+ writeSessionsLocked();
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0616460..38a2016 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -195,6 +195,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
this.internalStageDir = internalStageDir;
this.externalStageCid = externalStageCid;
+ if ((internalStageDir == null) == (externalStageCid == null)) {
+ throw new IllegalArgumentException(
+ "Exactly one of internal or external stage must be set");
+ }
+
mSealed = sealed;
// Always derived at runtime
@@ -395,7 +400,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
Preconditions.checkNotNull(statusReceiver);
final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
- statusReceiver);
+ statusReceiver, sessionId);
mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
}
@@ -414,8 +419,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
mSealed = true;
- // TODO: persist disabled mutations before going forward, since
- // beyond this point we may have hardlinks to the valid install
+ // Persist the fact that we've sealed ourselves to prevent mutations
+ // of any hard links we create below.
+ mCallback.onSessionSealed(this);
}
final File stageDir;
@@ -476,9 +482,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
};
- // TODO: send ASEC cid if that's where we staged things
- mPm.installStage(mPackageName, this.internalStageDir, null, localObserver, params,
- installerPackageName, installerUid, new UserHandle(userId));
+ mPm.installStage(mPackageName, this.internalStageDir, this.externalStageCid, localObserver,
+ params, installerPackageName, installerUid, new UserHandle(userId));
}
/**
@@ -486,6 +491,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
* consistent package name, version code, and signing certificates.
* <p>
* Renames package files in stage to match split names defined inside.
+ * <p>
+ * Note that upgrade compatibility is still performed by
+ * {@link PackageManagerService}.
*/
private void validateInstallLocked(File stageDir) throws PackageManagerException {
mPackageName = null;
@@ -498,13 +506,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
}
- final ArraySet<String> seenSplits = new ArraySet<>();
-
// Verify that all staged packages are internally consistent
+ final ArraySet<String> seenSplits = new ArraySet<>();
for (File file : files) {
+
+ // Installers can't stage directories, so it's fine to ignore
+ // entries like "lost+found".
+ if (file.isDirectory()) continue;
+
final ApkLite info;
try {
- info = PackageParser.parseApkLite(file, PackageParser.PARSE_GET_SIGNATURES);
+ info = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Failed to parse " + file + ": " + e);
@@ -550,10 +562,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- // TODO: shift package signature verification to installer; we're
- // currently relying on PMS to do this.
- // TODO: teach about compatible upgrade keysets.
-
if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Full installs must include a base package
if (!seenSplits.contains(null)) {
@@ -577,7 +585,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final ApkLite info;
try {
info = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
- PackageParser.PARSE_GET_SIGNATURES);
+ PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Failed to parse existing base " + app.getBaseCodePath() + ": " + e);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f47e64f..aa49b27 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -48,11 +48,6 @@ import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
-import static android.system.OsConstants.S_IRGRP;
-import static android.system.OsConstants.S_IROTH;
-import static android.system.OsConstants.S_IRWXU;
-import static android.system.OsConstants.S_IXGRP;
-import static android.system.OsConstants.S_IXOTH;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
import static com.android.internal.util.ArrayUtils.appendInt;
@@ -70,7 +65,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
import com.android.server.LocalServices;
@@ -255,10 +249,6 @@ public class PackageManagerService extends IPackageManager.Stub {
// package apks to install directory.
private static final String INSTALL_PACKAGE_SUFFIX = "-";
- // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate
- // that the cpuAbiOverride must be clear.
- private static final String CLEAR_ABI_OVERRIDE = "-";
-
static final int SCAN_MONITOR = 1<<0;
static final int SCAN_NO_DEX = 1<<1;
static final int SCAN_FORCE_DEX = 1<<2;
@@ -5022,7 +5012,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
String cpuAbiOverride = null;
- if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
+ if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
cpuAbiOverride = null;
} else if (abiOverride != null) {
cpuAbiOverride = abiOverride;
@@ -5526,7 +5516,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// 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 (pkg.cpuAbiOverride != null && !CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+ if (pkg.cpuAbiOverride != null
+ && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
}
@@ -5536,7 +5527,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isAsec) {
abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
} else {
- abi32 = copyNativeLibrariesForInternalApp(handle,
+ abi32 = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, useIsaSpecificSubdirs);
}
}
@@ -5548,7 +5539,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isAsec) {
abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
} else {
- abi64 = copyNativeLibrariesForInternalApp(handle,
+ abi64 = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, useIsaSpecificSubdirs);
}
}
@@ -5587,8 +5578,8 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isAsec) {
copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
} else {
- copyRet = copyNativeLibrariesForInternalApp(handle, nativeLibraryRoot, abiList,
- useIsaSpecificSubdirs);
+ copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
+ nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
}
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
@@ -6471,58 +6462,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- 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 nativeLibraryRoot, String[] abiList, boolean useIsaSubdir) throws IOException {
- createNativeLibrarySubdir(nativeLibraryRoot);
-
- /*
- * If this is an internal application or our nativeLibraryPath points to
- * the app-lib directory, unpack the libraries if necessary.
- */
- 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, subDir, abiList[abi]);
- if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
- return copyRet;
- }
- }
-
- return abi;
- }
-
private void killApplication(String pkgName, int appId, String reason) {
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
@@ -8667,6 +8606,20 @@ public class PackageManagerService extends IPackageManager.Stub {
*/
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
+
+ // If we're already staged, we've firmly committed to an install location
+ if (originStaged) {
+ if (originFile != null) {
+ flags |= PackageManager.INSTALL_INTERNAL;
+ flags &= ~PackageManager.INSTALL_EXTERNAL;
+ } else if (originCid != null) {
+ flags |= PackageManager.INSTALL_EXTERNAL;
+ flags &= ~PackageManager.INSTALL_INTERNAL;
+ } else {
+ throw new IllegalStateException("Invalid stage location");
+ }
+ }
+
final boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0;
PackageInfoLite pkgLite = null;
@@ -8690,7 +8643,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* If we have too little free space, try to free cache
* before giving up.
*/
- if (pkgLite.recommendedInstallLocation
+ if (!originStaged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// TODO: focus freeing disk space on the target device
final StorageManager storage = StorageManager.from(mContext);
@@ -9287,49 +9240,11 @@ public class PackageManagerService extends IPackageManager.Stub {
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
- 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 && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
- 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 */);
- maybeThrowExceptionForMultiArchCopy("Failure copying 32 bit native libraries", copyRet);
- }
-
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
- copyRet = copyNativeLibrariesForInternalApp(handle, libraryRoot,
- Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */);
- maybeThrowExceptionForMultiArchCopy("Failure copying 64 bit native libraries", copyRet);
- }
- } else {
- final String cpuAbiOverride = deriveAbiOverride(this.abiOverride, null /* package setting */);
- String[] abiList = (cpuAbiOverride != null) ?
- new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
-
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == 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;
- }
- }
+ ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, libraryRoot,
+ abiOverride, multiArch);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- } catch (PackageManagerException pme) {
- Slog.e(TAG, "Copying native libraries failed", pme);
- ret = pme.error;
} finally {
IoUtils.closeQuietly(handle);
}
@@ -9504,8 +9419,6 @@ public class PackageManagerService extends IPackageManager.Stub {
* renaming logic.
*/
class AsecInstallArgs extends InstallArgs {
- // TODO: teach about handling cluster directories
-
static final String RES_FILE_NAME = "pkg.apk";
static final String PUBLIC_RES_FILE_NAME = "res.zip";
@@ -9528,12 +9441,17 @@ public class PackageManagerService extends IPackageManager.Stub {
super(null, false, null, (isExternal ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, isMultiArch);
+ // Hackily pretend we're still looking at a full code path
+ if (!fullCodePath.endsWith(RES_FILE_NAME)) {
+ fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
+ }
+
// Extract cid from fullCodePath
int eidx = fullCodePath.lastIndexOf("/");
String subStr1 = fullCodePath.substring(0, eidx);
int sidx = subStr1.lastIndexOf("/");
cid = subStr1.substring(sidx+1, eidx);
- setCachePath(subStr1);
+ setMountPath(subStr1);
}
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked,
@@ -9542,7 +9460,7 @@ public class PackageManagerService extends IPackageManager.Stub {
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, isMultiArch);
this.cid = cid;
- setCachePath(PackageHelper.getSdDir(cid));
+ setMountPath(PackageHelper.getSdDir(cid));
}
/** New install from existing */
@@ -9564,7 +9482,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final File target;
if (isExternal()) {
- target = Environment.getExternalStorageDirectory();
+ target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory();
} else {
target = Environment.getDataDirectory();
}
@@ -9578,6 +9496,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+ // TODO: if already staged, we only need to extract native code
if (temp) {
createCopyFile();
} else {
@@ -9588,12 +9507,12 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageHelper.destroySdDir(cid);
}
- final String newCachePath = imcs.copyPackageToContainer(
+ final String newMountPath = imcs.copyPackageToContainer(
originFile.getAbsolutePath(), cid, getEncryptKey(), isExternal(),
isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
- if (newCachePath != null) {
- setCachePath(newCachePath);
+ if (newMountPath != null) {
+ setMountPath(newMountPath);
return PackageManager.INSTALL_SUCCEEDED;
} else {
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
@@ -9622,10 +9541,10 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
boolean mounted = PackageHelper.isContainerMounted(cid);
if (!mounted) {
- String newCachePath = PackageHelper.mountSdDir(cid, getEncryptKey(),
+ String newMountPath = PackageHelper.mountSdDir(cid, getEncryptKey(),
Process.SYSTEM_UID);
- if (newCachePath != null) {
- setCachePath(newCachePath);
+ if (newMountPath != null) {
+ setMountPath(newMountPath);
} else {
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
}
@@ -9636,7 +9555,7 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
String newCacheId = getNextCodePath(oldCodePath, pkg.packageName, "/" + RES_FILE_NAME);
- String newCachePath = null;
+ String newMountPath = null;
if (PackageHelper.isContainerMounted(cid)) {
// Unmount the container
if (!PackageHelper.unMountSdDir(cid)) {
@@ -9661,46 +9580,59 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (!PackageHelper.isContainerMounted(newCacheId)) {
Slog.w(TAG, "Mounting container " + newCacheId);
- newCachePath = PackageHelper.mountSdDir(newCacheId,
+ newMountPath = PackageHelper.mountSdDir(newCacheId,
getEncryptKey(), Process.SYSTEM_UID);
} else {
- newCachePath = PackageHelper.getSdDir(newCacheId);
+ newMountPath = PackageHelper.getSdDir(newCacheId);
}
- if (newCachePath == null) {
+ if (newMountPath == null) {
Slog.w(TAG, "Failed to get cache path for " + newCacheId);
return false;
}
Log.i(TAG, "Succesfully renamed " + cid +
" to " + newCacheId +
- " at new path: " + newCachePath);
+ " at new path: " + newMountPath);
cid = newCacheId;
- setCachePath(newCachePath);
-
- // TODO: extend to support split APKs
- pkg.codePath = getCodePath();
- pkg.baseCodePath = getCodePath();
- pkg.splitCodePaths = null;
- pkg.applicationInfo.setCodePath(getCodePath());
- pkg.applicationInfo.setBaseCodePath(getCodePath());
- pkg.applicationInfo.setSplitCodePaths(null);
- pkg.applicationInfo.setResourcePath(getResourcePath());
- pkg.applicationInfo.setBaseResourcePath(getResourcePath());
- pkg.applicationInfo.setSplitResourcePaths(null);
+ final File beforeCodeFile = new File(packagePath);
+ setMountPath(newMountPath);
+ final File afterCodeFile = new File(packagePath);
+
+ // Reflect the rename in scanned details
+ pkg.codePath = afterCodeFile.getAbsolutePath();
+ pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
+ pkg.baseCodePath);
+ pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
+ pkg.splitCodePaths);
+
+ // Reflect the rename in app info
+ pkg.applicationInfo.setCodePath(pkg.codePath);
+ pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
+ pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
+ pkg.applicationInfo.setResourcePath(pkg.codePath);
+ pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
+ pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
return true;
}
- private void setCachePath(String newCachePath) {
- File cachePath = new File(newCachePath);
- legacyNativeLibraryDir = new File(cachePath, LIB_DIR_NAME).getPath();
- packagePath = new File(cachePath, RES_FILE_NAME).getPath();
+ private void setMountPath(String mountPath) {
+ final File mountFile = new File(mountPath);
- if (isFwdLocked()) {
- resourcePath = new File(cachePath, PUBLIC_RES_FILE_NAME).getPath();
+ final File monolithicFile = new File(mountFile, RES_FILE_NAME);
+ if (monolithicFile.exists()) {
+ packagePath = monolithicFile.getAbsolutePath();
+ if (isFwdLocked()) {
+ resourcePath = new File(mountFile, PUBLIC_RES_FILE_NAME).getAbsolutePath();
+ } else {
+ resourcePath = packagePath;
+ }
} else {
+ packagePath = mountFile.getAbsolutePath();
resourcePath = packagePath;
}
+
+ legacyNativeLibraryDir = new File(mountFile, LIB_DIR_NAME).getAbsolutePath();
}
int doPostInstall(int status, int uid) {
@@ -9739,23 +9671,43 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageHelper.destroySdDir(cid);
}
- void cleanUpResourcesLI() {
- String sourceFile = getCodePath();
- // Remove dex file
- if (instructionSets == null) {
- throw new IllegalStateException("instructionSet == null");
- }
- String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- int retCode = mInstaller.rmdex(sourceFile, dexCodeInstructionSet);
- 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
+ private List<String> getAllCodePaths() {
+ final File codeFile = new File(getCodePath());
+ if (codeFile != null && codeFile.exists()) {
+ try {
+ final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
+ return pkg.getAllCodePaths();
+ } catch (PackageParserException e) {
+ // Ignored; we tried our best
}
}
+ return Collections.EMPTY_LIST;
+ }
+
+ void cleanUpResourcesLI() {
+ // Enumerate all code paths before deleting
+ cleanUpResourcesLI(getAllCodePaths());
+ }
+
+ private void cleanUpResourcesLI(List<String> allCodePaths) {
cleanUp();
+
+ if (!allCodePaths.isEmpty()) {
+ if (instructionSets == null) {
+ throw new IllegalStateException("instructionSet == null");
+ }
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String codePath : allCodePaths) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
+ 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
+ }
+ }
+ }
+ }
}
boolean matchContainer(String app) {
@@ -9770,16 +9722,19 @@ public class PackageManagerService extends IPackageManager.Stub {
}
boolean doPostDeleteLI(boolean delete) {
- boolean ret = false;
+ if (DEBUG_SD_INSTALL) Slog.i(TAG, "doPostDeleteLI() del=" + delete);
+ final List<String> allCodePaths = getAllCodePaths();
boolean mounted = PackageHelper.isContainerMounted(cid);
if (mounted) {
// Unmount first
- ret = PackageHelper.unMountSdDir(cid);
+ if (PackageHelper.unMountSdDir(cid)) {
+ mounted = false;
+ }
}
- if (ret && delete) {
- cleanUpResourcesLI();
+ if (!mounted && delete) {
+ cleanUpResourcesLI(allCodePaths);
}
- return ret;
+ return !mounted;
}
@Override
@@ -10966,6 +10921,7 @@ public class PackageManagerService extends IPackageManager.Stub {
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
getAppDexInstructionSets(ps), isMultiArch(ps));
+ if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
return true;
}
@@ -12772,7 +12728,8 @@ public class PackageManagerService extends IPackageManager.Stub {
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())) {
+ if (ps.codePathString != null
+ && ps.codePathString.startsWith(args.getCodePath())) {
if (DEBUG_SD_INSTALL) {
Log.i(TAG, "Container : " + cid + " corresponds to pkg : " + pkgName
+ " at code path: " + ps.codePathString);
@@ -12851,7 +12808,7 @@ public class PackageManagerService extends IPackageManager.Stub {
continue;
}
// Check code path here.
- if (codePath == null || !codePath.equals(args.getCodePath())) {
+ if (codePath == null || !codePath.startsWith(args.getCodePath())) {
Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()
+ " does not match one in settings " + codePath);
continue;