diff options
Diffstat (limited to 'services/core/java/com/android/server/pm/PackageManagerService.java')
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 640 |
1 files changed, 290 insertions, 350 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 89bd1d4..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; @@ -107,12 +101,12 @@ import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; -import android.content.pm.InstallSessionParams; import android.content.pm.InstrumentationInfo; import android.content.pm.ManifestDigest; import android.content.pm.PackageCleanItem; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.LegacyPackageDeleteObserver; import android.content.pm.PackageParser.ActivityIntentInfo; @@ -140,6 +134,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Environment.UserEnvironment; +import android.os.storage.StorageManager; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -211,6 +206,7 @@ import dalvik.system.StaleDexCacheError; import dalvik.system.VMRuntime; import libcore.io.IoUtils; +import libcore.util.EmptyArray; /** * Keep track of all those .apks everywhere. @@ -253,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; @@ -311,8 +303,6 @@ public class PackageManagerService extends IPackageManager.Stub { private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay"; - static final String mTempContainerPrefix = "smdl2tmp"; - private static String sPreferredInstructionSet; final ServiceThread mHandlerThread; @@ -1394,16 +1384,27 @@ public class PackageManagerService extends IPackageManager.Stub { * list of process files because dexopt will have been run * if necessary during zygote startup. */ - String bootClassPath = System.getProperty("java.boot.class.path"); + final String bootClassPath = System.getenv("BOOTCLASSPATH"); + final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH"); + if (bootClassPath != null) { - String[] paths = splitString(bootClassPath, ':'); - for (int i=0; i<paths.length; i++) { - alreadyDexOpted.add(paths[i]); + String[] bootClassPathElements = splitString(bootClassPath, ':'); + for (String element : bootClassPathElements) { + alreadyDexOpted.add(element); } } else { Slog.w(TAG, "No BOOTCLASSPATH found!"); } + if (systemServerClassPath != null) { + String[] systemServerClassPathElements = splitString(systemServerClassPath, ':'); + for (String element : systemServerClassPathElements) { + alreadyDexOpted.add(element); + } + } else { + Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!"); + } + boolean didDexOptLibraryOrTool = false; final List<String> allInstructionSets = getAllInstructionSets(); @@ -2920,7 +2921,8 @@ public class PackageManagerService extends IPackageManager.Stub { findPreferredActivity(intent, resolvedType, flags, query, 0, false, true, false, userId); // Add the new activity as the last chosen for this filter - addPreferredActivityInternal(filter, match, null, activity, false, userId); + addPreferredActivityInternal(filter, match, null, activity, false, userId, + "Setting last chosen"); } @Override @@ -3192,24 +3194,22 @@ public class PackageManagerService extends IPackageManager.Stub { if (matches.get(i).getTargetUserId() == targetUserId) return true; } } - ArrayList<String> packageNames = null; SparseArray<ArrayList<String>> fromSource = mSettings.mCrossProfilePackageInfo.get(sourceUserId); if (fromSource != null) { packageNames = fromSource.get(targetUserId); - } - if (packageNames != null && packageNames.contains(intent.getPackage())) { - return true; - } - // We need the package name, so we try to resolve with the loosest flags possible - List<ResolveInfo> resolveInfos = mActivities.queryIntent( - intent, resolvedType, PackageManager.GET_UNINSTALLED_PACKAGES, targetUserId); - int count = resolveInfos.size(); - for (int i = 0; i < count; i++) { - ResolveInfo resolveInfo = resolveInfos.get(i); - if (packageNames.contains(resolveInfo.activityInfo.packageName)) { - return true; + if (packageNames != null) { + // We need the package name, so we try to resolve with the loosest flags possible + List<ResolveInfo> resolveInfos = mActivities.queryIntent(intent, resolvedType, + PackageManager.GET_UNINSTALLED_PACKAGES, targetUserId); + int count = resolveInfos.size(); + for (int i = 0; i < count; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + if (packageNames.contains(resolveInfo.activityInfo.packageName)) { + return true; + } + } } } return false; @@ -3282,6 +3282,7 @@ public class PackageManagerService extends IPackageManager.Stub { intent, resolvedType, flags, userId); if (resolveInfo != null) { result.add(resolveInfo); + Collections.sort(result, mResolvePrioritySorter); } return result; } @@ -4091,21 +4092,24 @@ public class PackageManagerService extends IPackageManager.Stub { for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) - && !PackageInstallerService.isStageFile(file); + && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { - // Ignore entries which are not apk's + // Ignore entries which are not packages continue; } try { - scanPackageLI(file, flags | PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); + scanPackageLI(file, flags | PackageParser.PARSE_MUST_BE_APK, + scanMode, currentTime, null); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage()); - // Don't mess around with apps in system partition. + // Delete invalid userdata apps if ((flags & PackageParser.PARSE_IS_SYSTEM) == 0 && e.error == PackageManager.INSTALL_FAILED_INVALID_APK) { - // Delete the apk - Slog.w(TAG, "Cleaning up failed install of " + file); + Slog.w(TAG, "Deleting invalid package at " + file); + if (file.isDirectory()) { + FileUtils.deleteContents(file); + } file.delete(); } } @@ -5008,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; @@ -5512,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."); } @@ -5522,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); } } @@ -5534,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); } } @@ -5573,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) { @@ -6457,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 @@ -7829,19 +7782,19 @@ public class PackageManagerService extends IPackageManager.Stub { verificationParams.setInstallerUid(uid); final Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = new InstallParams(originFile, false, observer, filteredFlags, + msg.obj = new InstallParams(originFile, null, false, observer, filteredFlags, installerPackageName, verificationParams, user, packageAbiOverride); mHandler.sendMessage(msg); } - void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer, - InstallSessionParams params, String installerPackageName, int installerUid, - UserHandle user) { + void installStage(String packageName, File stagedDir, String stagedCid, + IPackageInstallObserver2 observer, PackageInstaller.SessionParams params, + String installerPackageName, int installerUid, UserHandle user) { final VerificationParams verifParams = new VerificationParams(null, params.originatingUri, params.referrerUri, installerUid, null); final Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = new InstallParams(stageDir, true, observer, params.installFlags, + msg.obj = new InstallParams(stagedDir, stagedCid, true, observer, params.installFlags, installerPackageName, verifParams, user, params.abiOverride); mHandler.sendMessage(msg); } @@ -8541,10 +8494,12 @@ public class PackageManagerService extends IPackageManager.Stub { * file, or a cluster directory. This location may be untrusted. */ final File originFile; + final String originCid; /** - * Flag indicating that {@link #originFile} has already been staged, - * meaning downstream users don't need to defensively copy the contents. + * Flag indicating that {@link #originFile} or {@link #originCid} has + * already been staged, meaning downstream users don't need to + * defensively copy the contents. */ boolean originStaged; @@ -8557,11 +8512,12 @@ public class PackageManagerService extends IPackageManager.Stub { final String packageAbiOverride; boolean multiArch; - InstallParams(File originFile, boolean originStaged, IPackageInstallObserver2 observer, - int flags, String installerPackageName, VerificationParams verificationParams, - UserHandle user, String packageAbiOverride) { + InstallParams(File originFile, String originCid, boolean originStaged, + IPackageInstallObserver2 observer, int flags, String installerPackageName, + VerificationParams verificationParams, UserHandle user, String packageAbiOverride) { super(user); - this.originFile = Preconditions.checkNotNull(originFile); + this.originFile = originFile; + this.originCid = originCid; this.originStaged = originStaged; this.observer = observer; this.flags = flags; @@ -8572,9 +8528,8 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public String toString() { - return "InstallParams{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + originFile + "}"; + return "InstallParams{" + Integer.toHexString(System.identityHashCode(this)) + + " file=" + originFile + " cid=" + originCid + "}"; } public ManifestDigest getManifestDigest() { @@ -8643,15 +8598,6 @@ public class PackageManagerService extends IPackageManager.Stub { return pkgLite.recommendedInstallLocation; } - private long getMemoryLowThreshold() { - final DeviceStorageMonitorInternal - dsm = LocalServices.getService(DeviceStorageMonitorInternal.class); - if (dsm == null) { - return 0L; - } - return dsm.getMemoryLowThreshold(); - } - /* * Invoke remote method to get package information and install * location values. Override install location based on default @@ -8660,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; @@ -8669,14 +8629,9 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { - final long lowThreshold = getMemoryLowThreshold(); - if (lowThreshold == 0L) { - Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed"); - } - // Remote call to find out default install location final String originPath = originFile.getAbsolutePath(); - pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags, lowThreshold, + pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags, 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 @@ -8688,14 +8643,21 @@ 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) { - final long size = mContainerService.calculateInstalledSize( + // TODO: focus freeing disk space on the target device + final StorageManager storage = StorageManager.from(mContext); + final long lowThreshold = storage.getStorageLowBytes( + Environment.getDataDirectory()); + + final long sizeBytes = mContainerService.calculateInstalledSize( originPath, isForwardLocked(), packageAbiOverride); - if (mInstaller.freeCache(size + lowThreshold) >= 0) { + + if (mInstaller.freeCache(sizeBytes + lowThreshold) >= 0) { pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags, - lowThreshold, packageAbiOverride); + packageAbiOverride); } + /* * The cache free must have deleted the file we * downloaded to install. @@ -9225,24 +9187,11 @@ public class PackageManagerService extends IPackageManager.Stub { } boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { - final long lowThreshold; + final long sizeBytes = imcs.calculateInstalledSize(originFile.getAbsolutePath(), + isFwdLocked(), abiOverride); - final DeviceStorageMonitorInternal - dsm = LocalServices.getService(DeviceStorageMonitorInternal.class); - if (dsm == null) { - Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed"); - lowThreshold = 0L; - } else { - if (dsm.isMemoryLow()) { - Log.w(TAG, "Memory is reported as being too low; aborting package install"); - return false; - } - - lowThreshold = dsm.getMemoryLowThreshold(); - } - - return imcs.checkInternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(), - lowThreshold); + final StorageManager storage = StorageManager.from(mContext); + return (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getDataDirectory())); } int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { @@ -9254,7 +9203,7 @@ public class PackageManagerService extends IPackageManager.Stub { resourceFile = originFile; } else { try { - final File tempDir = mInstallerService.allocateSessionDir(); + final File tempDir = mInstallerService.allocateInternalStageDirLegacy(); codeFile = tempDir; resourceFile = tempDir; } catch (IOException e) { @@ -9291,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); } @@ -9508,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"; @@ -9532,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, @@ -9546,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 */ @@ -9559,12 +9473,22 @@ public class PackageManagerService extends IPackageManager.Stub { } void createCopyFile() { - cid = getTempContainerId(); + cid = mInstallerService.allocateExternalStageCidLegacy(); } boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { - return imcs.checkExternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(), + final long sizeBytes = imcs.calculateInstalledSize(packagePath, isFwdLocked(), abiOverride); + + final File target; + if (isExternal()) { + target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory(); + } else { + target = Environment.getDataDirectory(); + } + + final StorageManager storage = StorageManager.from(mContext); + return (sizeBytes <= storage.getStorageBytesUntilLow(target)); } private final boolean isExternal() { @@ -9572,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 { @@ -9582,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; @@ -9616,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; } @@ -9630,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)) { @@ -9655,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) { @@ -9733,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) { @@ -9764,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 @@ -10960,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; } @@ -11462,11 +11424,13 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity, int userId) { - addPreferredActivityInternal(filter, match, set, activity, true, userId); + addPreferredActivityInternal(filter, match, set, activity, true, userId, + "Adding preferred"); } private void addPreferredActivityInternal(IntentFilter filter, int match, - ComponentName[] set, ComponentName activity, boolean always, int userId) { + ComponentName[] set, ComponentName activity, boolean always, int userId, + String opname) { // writer int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true, "add preferred activity"); @@ -11488,10 +11452,11 @@ public class PackageManagerService extends IPackageManager.Stub { android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } - Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :"); + PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId); + Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user " + + userId + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); - mSettings.editPreferredActivitiesLPw(userId).addFilter( - new PreferredActivity(filter, match, set, activity, always)); + pir.addFilter(new PreferredActivity(filter, match, set, activity, always)); mSettings.writePackageRestrictionsLPr(userId); } } @@ -11514,7 +11479,6 @@ public class PackageManagerService extends IPackageManager.Stub { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true, "replace preferred activity"); - final int callingUserId = UserHandle.getUserId(callingUid); synchronized (mPackages) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) @@ -11529,30 +11493,63 @@ public class PackageManagerService extends IPackageManager.Stub { android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } - PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId); + PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); if (pir != null) { - Intent intent = new Intent(filter.getAction(0)).addCategory(filter.getCategory(0)); - if (filter.countDataSchemes() == 1) { - Uri.Builder builder = new Uri.Builder(); - builder.scheme(filter.getDataScheme(0)); - intent.setData(builder.build()); - } - List<PreferredActivity> matches = pir.queryIntent( - intent, null, true, callingUserId); - if (DEBUG_PREFERRED) { - Slog.i(TAG, matches.size() + " preferred matches for " + intent); - } - for (int i = 0; i < matches.size(); i++) { - PreferredActivity pa = matches.get(i); + // Get all of the existing entries that exactly match this filter. + ArrayList<PreferredActivity> existing = pir.findFilters(filter); + if (existing != null && existing.size() == 1) { + PreferredActivity cur = existing.get(0); if (DEBUG_PREFERRED) { - Slog.i(TAG, "Removing preferred activity " - + pa.mPref.mComponent + ":"); + Slog.i(TAG, "Checking replace of preferred:"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); + if (!cur.mPref.mAlways) { + Slog.i(TAG, " -- CUR; not mAlways!"); + } else { + Slog.i(TAG, " -- CUR: mMatch=" + cur.mPref.mMatch); + Slog.i(TAG, " -- CUR: mSet=" + + Arrays.toString(cur.mPref.mSetComponents)); + Slog.i(TAG, " -- CUR: mComponent=" + cur.mPref.mShortComponent); + Slog.i(TAG, " -- NEW: mMatch=" + + (match&IntentFilter.MATCH_CATEGORY_MASK)); + Slog.i(TAG, " -- CUR: mSet=" + Arrays.toString(set)); + Slog.i(TAG, " -- CUR: mComponent=" + activity.flattenToShortString()); + } + } + if (cur.mPref.mAlways && cur.mPref.mComponent.equals(activity) + && cur.mPref.mMatch == (match&IntentFilter.MATCH_CATEGORY_MASK) + && cur.mPref.sameSet(set)) { + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Replacing with same preferred activity " + + cur.mPref.mShortComponent + " for user " + + userId + ":"); + filter.dump(new LogPrinter(Log.INFO, TAG), " "); + } else { + Slog.i(TAG, "Replacing with same preferred activity " + + cur.mPref.mShortComponent + " for user " + + userId); + } + return; + } + } + + if (existing != null) { + if (DEBUG_PREFERRED) { + Slog.i(TAG, existing.size() + " existing preferred matches for:"); + filter.dump(new LogPrinter(Log.INFO, TAG), " "); + } + for (int i = 0; i < existing.size(); i++) { + PreferredActivity pa = existing.get(i); + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Removing existing preferred activity " + + pa.mPref.mComponent + ":"); + pa.dump(new LogPrinter(Log.INFO, TAG), " "); + } + pir.removeFilter(pa); } - pir.removeFilter(pa); } } - addPreferredActivityInternal(filter, match, set, activity, true, callingUserId); + addPreferredActivityInternal(filter, match, set, activity, true, userId, + "Replacing preferred"); } } @@ -12610,7 +12607,7 @@ public class PackageManagerService extends IPackageManager.Stub { private boolean mMediaMounted = false; - private String getEncryptKey() { + static String getEncryptKey() { try { String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString( SD_ENCRYPTION_KEYSTORE_NAME); @@ -12630,30 +12627,6 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe); return null; } - - } - - /* package */static String getTempContainerId() { - int tmpIdx = 1; - String list[] = PackageHelper.getSecureContainerList(); - if (list != null) { - for (final String name : list) { - // Ignore null and non-temporary container entries - if (name == null || !name.startsWith(mTempContainerPrefix)) { - continue; - } - - String subStr = name.substring(mTempContainerPrefix.length()); - try { - int cid = Integer.parseInt(subStr); - if (cid >= tmpIdx) { - tmpIdx = cid + 1; - } - } catch (NumberFormatException e) { - } - } - } - return mTempContainerPrefix + tmpIdx; } /* @@ -12711,31 +12684,27 @@ public class PackageManagerService extends IPackageManager.Stub { */ private void updateExternalMediaStatusInner(boolean isMounted, boolean reportStatus, boolean externalStorage) { - // Collection of uids - int uidArr[] = null; - // Collection of stale containers - HashSet<String> removeCids = new HashSet<String>(); - // Collection of packages on external media with valid containers. - HashMap<AsecInstallArgs, String> processCids = new HashMap<AsecInstallArgs, String>(); - // Get list of secure containers. - final String list[] = PackageHelper.getSecureContainerList(); - if (list == null || list.length == 0) { - Log.i(TAG, "No secure containers on sdcard"); + ArrayMap<AsecInstallArgs, String> processCids = new ArrayMap<>(); + int[] uidArr = EmptyArray.INT; + + final String[] list = PackageHelper.getSecureContainerList(); + if (ArrayUtils.isEmpty(list)) { + Log.i(TAG, "No secure containers found"); } else { // Process list of secure containers and categorize them // as active or stale based on their package internal state. - int uidList[] = new int[list.length]; - int num = 0; + // reader synchronized (mPackages) { for (String cid : list) { + // Leave stages untouched for now; installer service owns them + if (PackageInstallerService.isStageName(cid)) continue; + if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid); String pkgName = getAsecPackageName(cid); if (pkgName == null) { - if (DEBUG_SD_INSTALL) - Log.i(TAG, "Container : " + cid + " stale"); - removeCids.add(cid); + Slog.i(TAG, "Found stale container " + cid + " with no package name"); continue; } if (DEBUG_SD_INSTALL) @@ -12743,8 +12712,7 @@ public class PackageManagerService extends IPackageManager.Stub { final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps == null) { - Log.i(TAG, "Deleting container with no matching settings " + cid); - removeCids.add(cid); + Slog.i(TAG, "Found stale container " + cid + " with no matching settings"); continue; } @@ -12760,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); @@ -12770,35 +12739,25 @@ public class PackageManagerService extends IPackageManager.Stub { processCids.put(args, ps.codePathString); final int uid = ps.appId; if (uid != -1) { - uidList[num++] = uid; + uidArr = ArrayUtils.appendInt(uidArr, uid); } } else { - Log.i(TAG, "Deleting stale container for " + cid); - removeCids.add(cid); + Slog.i(TAG, "Found stale container " + cid + ": expected codePath=" + + ps.codePathString); } } } - if (num > 0) { - // Sort uid list - Arrays.sort(uidList, 0, num); - // Throw away duplicates - uidArr = new int[num]; - uidArr[0] = uidList[0]; - int di = 0; - for (int i = 1; i < num; i++) { - if (uidList[i - 1] != uidList[i]) { - uidArr[di++] = uidList[i]; - } - } - } + Arrays.sort(uidArr); } + // Process packages with valid entries. if (isMounted) { if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages"); - loadMediaPackages(processCids, uidArr, removeCids); + loadMediaPackages(processCids, uidArr); startCleaningPackages(); + mInstallerService.onSecureContainersAvailable(); } else { if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages"); @@ -12806,8 +12765,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, - ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) { + private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, + ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) { int size = pkgList.size(); if (size > 0) { // Send broadcasts here @@ -12832,11 +12791,10 @@ public class PackageManagerService extends IPackageManager.Stub { * the cid is added to list of removeCids. We currently don't delete stale * containers. */ - private void loadMediaPackages(HashMap<AsecInstallArgs, String> processCids, int uidArr[], - HashSet<String> removeCids) { + private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr) { ArrayList<String> pkgList = new ArrayList<String>(); Set<AsecInstallArgs> keys = processCids.keySet(); - boolean doGc = false; + for (AsecInstallArgs args : keys) { String codePath = processCids.get(args); if (DEBUG_SD_INSTALL) @@ -12850,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; @@ -12864,7 +12822,6 @@ public class PackageManagerService extends IPackageManager.Stub { parseFlags |= PackageParser.PARSE_FORWARD_LOCK; } - doGc = true; synchronized (mInstallLock) { PackageParser.Package pkg = null; try { @@ -12894,9 +12851,7 @@ public class PackageManagerService extends IPackageManager.Stub { } finally { if (retCode != PackageManager.INSTALL_SUCCEEDED) { - // Don't destroy container here. Wait till gc clears things - // up. - removeCids.add(args.cid); + Log.w(TAG, "Container " + args.cid + " is stale, retCode=" + retCode); } } } @@ -12931,21 +12886,6 @@ public class PackageManagerService extends IPackageManager.Stub { if (pkgList.size() > 0) { sendResourcesChangedBroadcast(true, false, pkgList, uidArr, null); } - // Force gc to avoid any stale parser references that we might have. - if (doGc) { - Runtime.getRuntime().gc(); - } - // List stale containers and destroy stale temporary containers. - if (removeCids != null) { - for (String cid : removeCids) { - if (cid.startsWith(mTempContainerPrefix)) { - Log.i(TAG, "Destroying stale temporary container " + cid); - PackageHelper.destroySdDir(cid); - } else { - Log.w(TAG, "Container " + cid + " is stale"); - } - } - } } /* @@ -12969,7 +12909,7 @@ public class PackageManagerService extends IPackageManager.Stub { * that we always have to post this message if status has been requested no * matter what. */ - private void unloadMediaPackages(HashMap<AsecInstallArgs, String> processCids, int uidArr[], + private void unloadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int uidArr[], final boolean reportStatus) { if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages"); |