diff options
15 files changed, 748 insertions, 825 deletions
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java index 84c7c5513319..da8992ae77f8 100644 --- a/services/core/java/com/android/server/pm/AppDataHelper.java +++ b/services/core/java/com/android/server/pm/AppDataHelper.java @@ -88,6 +88,7 @@ final class AppDataHelper { * <p> * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em> */ + @GuardedBy("mPm.mInstallLock") public void prepareAppDataAfterInstallLIF(AndroidPackage pkg) { prepareAppDataPostCommitLIF(pkg, 0 /* previousAppId */); } @@ -97,6 +98,7 @@ final class AppDataHelper { * {@link #prepareAppData(Installer.Batch, AndroidPackage, int, int, int)} * @see #prepareAppDataAfterInstallLIF(AndroidPackage) */ + @GuardedBy("mPm.mInstallLock") public void prepareAppDataPostCommitLIF(AndroidPackage pkg, int previousAppId) { final PackageSetting ps; synchronized (mPm.mLock) { diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index 075fb47cceac..48ec436761e9 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -271,7 +271,7 @@ final class DeletePackageHelper { // other processes clean up before deleting resources. synchronized (mPm.mInstallLock) { if (info.mArgs != null) { - info.mArgs.doPostDeleteLI(true); + mRemovePackageHelper.cleanUpResources(info.mArgs); } boolean reEnableStub = false; @@ -341,6 +341,7 @@ final class DeletePackageHelper { /* * This method handles package deletion in general */ + @GuardedBy("mPm.mInstallLock") public boolean deletePackageLIF(@NonNull String packageName, UserHandle user, boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags, PackageRemovedInfo outInfo, boolean writeSettings) { @@ -393,8 +394,18 @@ final class DeletePackageHelper { return new DeletePackageAction(ps, disabledPs, outInfo, flags, user); } + public void executeDeletePackage(DeletePackageAction action, String packageName, + boolean deleteCodeAndResources, @NonNull int[] allUserHandles, boolean writeSettings) + throws SystemDeleteException { + synchronized (mPm.mInstallLock) { + executeDeletePackageLIF(action, packageName, deleteCodeAndResources, allUserHandles, + writeSettings); + } + } + /** Deletes a package. Only throws when install of a disabled package fails. */ - public void executeDeletePackageLIF(DeletePackageAction action, + @GuardedBy("mPm.mInstallLock") + private void executeDeletePackageLIF(DeletePackageAction action, String packageName, boolean deleteCodeAndResources, @NonNull int[] allUserHandles, boolean writeSettings) throws SystemDeleteException { final PackageSetting ps = action.mDeletingPs; @@ -487,7 +498,9 @@ final class DeletePackageHelper { // Take a note whether we deleted the package for all users if (outInfo != null) { - outInfo.mRemovedForAllUsers = mPm.mPackages.get(ps.getPackageName()) == null; + synchronized (mPm.mLock) { + outInfo.mRemovedForAllUsers = mPm.mPackages.get(ps.getPackageName()) == null; + } } } @@ -538,6 +551,7 @@ final class DeletePackageHelper { } } + @GuardedBy("mPm.mInstallLock") private void deleteInstalledPackageLIF(PackageSetting ps, boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles, PackageRemovedInfo outInfo, boolean writeSettings) { @@ -556,7 +570,7 @@ final class DeletePackageHelper { // Delete application code and resources only for parent packages if (deleteCodeAndResources && (outInfo != null)) { - outInfo.mArgs = new FileInstallArgs( + outInfo.mArgs = new InstallArgs( ps.getPathString(), getAppDexInstructionSets( ps.getPrimaryCpuAbi(), ps.getSecondaryCpuAbi()), mPm); if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.mArgs); @@ -636,7 +650,10 @@ final class DeletePackageHelper { flags |= PackageManager.DELETE_KEEP_DATA; } - deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles, outInfo, writeSettings); + synchronized (mPm.mInstallLock) { + deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles, outInfo, + writeSettings); + } } public void deletePackageVersionedInternal(VersionedPackage versionedPackage, diff --git a/services/core/java/com/android/server/pm/FileInstallArgs.java b/services/core/java/com/android/server/pm/FileInstallArgs.java deleted file mode 100644 index 4d9e2a311ce2..000000000000 --- a/services/core/java/com/android/server/pm/FileInstallArgs.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm; - -import static android.app.AppOpsManager.MODE_DEFAULT; -import static android.content.pm.PackageManager.INSTALL_STAGED; -import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; -import static android.os.incremental.IncrementalManager.isIncrementalPath; - -import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; -import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; -import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; -import static com.android.server.pm.PackageManagerService.TAG; -import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive; - -import android.content.pm.DataLoaderType; -import android.content.pm.PackageInstaller; -import android.content.pm.PackageManager; -import android.content.pm.SigningDetails; -import android.content.pm.parsing.ApkLiteParseUtils; -import android.content.pm.parsing.PackageLite; -import android.content.pm.parsing.result.ParseResult; -import android.content.pm.parsing.result.ParseTypeImpl; -import android.os.Environment; -import android.os.FileUtils; -import android.os.SELinux; -import android.os.Trace; -import android.system.ErrnoException; -import android.system.Os; -import android.util.Slog; - -import com.android.internal.content.NativeLibraryHelper; -import com.android.server.pm.parsing.pkg.ParsedPackage; - -import libcore.io.IoUtils; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -/** - * Logic to handle installation of new applications, including copying - * and renaming logic. - */ -class FileInstallArgs extends InstallArgs { - private File mCodeFile; - - // Example topology: - // /data/app/com.example/base.apk - // /data/app/com.example/split_foo.apk - // /data/app/com.example/lib/arm/libfoo.so - // /data/app/com.example/lib/arm64/libfoo.so - // /data/app/com.example/dalvik/arm/base.apk@classes.dex - - /** New install */ - FileInstallArgs(InstallingSession params) { - super(params); - } - - /** - * Create args that describe an existing installed package. Typically used - * when cleaning up old installs, or used as a move source. - */ - FileInstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) { - super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, - null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0, - SigningDetails.UNKNOWN, - PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT, - false, DataLoaderType.NONE, - PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, pm); - mCodeFile = (codePath != null) ? new File(codePath) : null; - } - - int copyApk() { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk"); - try { - return doCopyApk(); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - private int doCopyApk() { - if (mOriginInfo.mStaged) { - if (DEBUG_INSTALL) Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy"); - mCodeFile = mOriginInfo.mFile; - return PackageManager.INSTALL_SUCCEEDED; - } - - try { - final boolean isEphemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0; - final File tempDir = - mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral); - mCodeFile = tempDir; - } catch (IOException e) { - Slog.w(TAG, "Failed to create copy file: " + e); - return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } - - int ret = PackageManagerServiceUtils.copyPackage( - mOriginInfo.mFile.getAbsolutePath(), mCodeFile); - if (ret != PackageManager.INSTALL_SUCCEEDED) { - Slog.e(TAG, "Failed to copy package"); - return ret; - } - - final boolean isIncremental = isIncrementalPath(mCodeFile.getAbsolutePath()); - final File libraryRoot = new File(mCodeFile, LIB_DIR_NAME); - NativeLibraryHelper.Handle handle = null; - try { - handle = NativeLibraryHelper.Handle.create(mCodeFile); - ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, - mAbiOverride, isIncremental); - } catch (IOException e) { - Slog.e(TAG, "Copying native libraries failed", e); - ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; - } finally { - IoUtils.closeQuietly(handle); - } - - return ret; - } - - int doPreInstall(int status) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(); - } - return status; - } - - @Override - boolean doRename(int status, ParsedPackage parsedPackage) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(); - return false; - } - - final File targetDir = resolveTargetDir(); - final File beforeCodeFile = mCodeFile; - final File afterCodeFile = PackageManagerServiceUtils.getNextCodePath(targetDir, - parsedPackage.getPackageName()); - - if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); - final boolean onIncremental = mPm.mIncrementalManager != null - && isIncrementalPath(beforeCodeFile.getAbsolutePath()); - try { - makeDirRecursive(afterCodeFile.getParentFile(), 0775); - if (onIncremental) { - // Just link files here. The stage dir will be removed when the installation - // session is completed. - mPm.mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile); - } else { - Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath()); - } - } catch (IOException | ErrnoException e) { - Slog.w(TAG, "Failed to rename", e); - return false; - } - - if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) { - Slog.w(TAG, "Failed to restorecon"); - return false; - } - - // Reflect the rename internally - mCodeFile = afterCodeFile; - - // Reflect the rename in scanned details - try { - parsedPackage.setPath(afterCodeFile.getCanonicalPath()); - } catch (IOException e) { - Slog.e(TAG, "Failed to get path: " + afterCodeFile, e); - return false; - } - parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile, - afterCodeFile, parsedPackage.getBaseApkPath())); - parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, - afterCodeFile, parsedPackage.getSplitCodePaths())); - - return true; - } - - // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged - // flow, we won't need this method anymore. - private File resolveTargetDir() { - boolean isStagedInstall = (mInstallFlags & INSTALL_STAGED) != 0; - if (isStagedInstall) { - return Environment.getDataAppDirectory(null); - } else { - return mCodeFile.getParentFile(); - } - } - - int doPostInstall(int status, int uid) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(); - } - return status; - } - - @Override - String getCodePath() { - return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null; - } - - private boolean cleanUp() { - if (mCodeFile == null || !mCodeFile.exists()) { - return false; - } - mRemovePackageHelper.removeCodePathLI(mCodeFile); - return true; - } - - void cleanUpResourcesLI() { - // Try enumerating all code paths before deleting - List<String> allCodePaths = Collections.EMPTY_LIST; - if (mCodeFile != null && mCodeFile.exists()) { - final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); - final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( - input.reset(), mCodeFile, /* flags */ 0); - if (result.isSuccess()) { - // Ignore error; we tried our best - allCodePaths = result.getResult().getAllApkPaths(); - } - } - - cleanUp(); - removeDexFiles(allCodePaths, mInstructionSets); - } - - void removeDexFiles(List<String> allCodePaths, String[] instructionSets) { - if (!allCodePaths.isEmpty()) { - if (instructionSets == null) { - throw new IllegalStateException("instructionSet == null"); - } - String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); - for (String codePath : allCodePaths) { - for (String dexCodeInstructionSet : dexCodeInstructionSets) { - try { - mPm.mInstaller.rmdex(codePath, dexCodeInstructionSet); - } catch (Installer.InstallerException ignored) { - } - } - } - } - } - - boolean doPostDeleteLI(boolean delete) { - // XXX err, shouldn't we respect the delete flag? - cleanUpResourcesLI(); - return true; - } -} diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java index fa8a9756c179..616bb8f419dd 100644 --- a/services/core/java/com/android/server/pm/InstallArgs.java +++ b/services/core/java/com/android/server/pm/InstallArgs.java @@ -16,19 +16,24 @@ package com.android.server.pm; +import static android.app.AppOpsManager.MODE_DEFAULT; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.DataLoaderType; import android.content.pm.IPackageInstallObserver2; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.SigningDetails; import android.os.UserHandle; import com.android.internal.util.Preconditions; -import com.android.server.pm.parsing.pkg.ParsedPackage; +import java.io.File; import java.util.List; -abstract class InstallArgs { +final class InstallArgs { + File mCodeFile; /** @see InstallingSession#mOriginInfo */ final OriginInfo mOriginInfo; /** @see InstallingSession#mMoveInfo */ @@ -108,28 +113,21 @@ abstract class InstallArgs { params.mDataLoaderType, params.mPackageSource, params.mPm); } - abstract int copyApk(); - abstract int doPreInstall(int status); - /** - * Rename package into final resting place. All paths on the given - * scanned package should be updated to reflect the rename. + * Create args that describe an existing installed package. Typically used + * when cleaning up old installs, or used as a move source. */ - abstract boolean doRename(int status, ParsedPackage parsedPackage); - abstract int doPostInstall(int status, int uid); - - /** @see PackageSettingBase#getPath() */ - abstract String getCodePath(); - - // Need installer lock especially for dex file removal. - abstract void cleanUpResourcesLI(); - abstract boolean doPostDeleteLI(boolean delete); - - protected boolean isEphemeral() { - return (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0; + InstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) { + this(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, + null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0, + SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN, + PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE, + PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, pm); + mCodeFile = (codePath != null) ? new File(codePath) : null; } - UserHandle getUser() { - return mUser; + /** @see PackageSettingBase#getPath() */ + String getCodePath() { + return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null; } } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index d68cecb41190..379b132545ae 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -34,6 +34,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_UID_CHANGED; import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE; import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP; +import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN; import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4; @@ -89,6 +90,7 @@ import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists; import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride; import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo; +import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive; import static com.android.server.pm.SharedUidMigration.BEST_EFFORT; import android.annotation.NonNull; @@ -123,9 +125,11 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.os.FileUtils; import android.os.Message; import android.os.Process; import android.os.RemoteException; +import android.os.SELinux; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; @@ -135,6 +139,8 @@ import android.os.incremental.IncrementalStorage; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.stats.storage.StorageEnums; +import android.system.ErrnoException; +import android.system.Os; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; @@ -236,7 +242,7 @@ final class InstallPackageHelper { * This needs to be fixed so, once we get to this point, no errors are * possible and the system is not left in an inconsistent state. */ - @GuardedBy({"mPm.mLock", "mPm.mInstallLock"}) + @GuardedBy("mPm.mLock") public AndroidPackage commitReconciledScanResultLocked( @NonNull ReconciledPackage reconciledPkg, int[] allUsers) { final ScanResult result = reconciledPkg.mScanResult; @@ -347,7 +353,7 @@ final class InstallPackageHelper { || (oldPkgSetting != null && oldPkgSetting.getUsesLibraryInfos() != null)) { // Reconcile if the new package or the old package uses shared libraries. // It is possible that the old package uses shared libraries but the new one doesn't. - mSharedLibraries.executeSharedLibrariesUpdateLPw(pkg, pkgSetting, null, null, + mSharedLibraries.executeSharedLibrariesUpdate(pkg, pkgSetting, null, null, reconciledPkg.mCollectedSharedLibraryInfos, allUsers); } @@ -365,8 +371,10 @@ final class InstallPackageHelper { for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) { final String codePathString = changedAbiCodePath.get(i); try { - mPm.mInstaller.rmdex(codePathString, - getDexCodeInstructionSet(getPreferredInstructionSet())); + synchronized (mPm.mInstallLock) { + mPm.mInstaller.rmdex(codePathString, + getDexCodeInstructionSet(getPreferredInstructionSet())); + } } catch (Installer.InstallerException ignored) { } } @@ -405,30 +413,12 @@ final class InstallPackageHelper { mPm.setPlatformPackage(pkg, pkgSetting); } - ArrayList<AndroidPackage> clientLibPkgs = null; // writer - synchronized (mPm.mLock) { - if (!ArrayUtils.isEmpty(reconciledPkg.mAllowedSharedLibraryInfos)) { - for (SharedLibraryInfo info : reconciledPkg.mAllowedSharedLibraryInfos) { - mSharedLibraries.commitSharedLibraryInfoLPw(info); - } - final Map<String, AndroidPackage> combinedSigningDetails = - reconciledPkg.getCombinedAvailablePackages(); - try { - // Shared libraries for the package need to be updated. - mSharedLibraries.updateSharedLibrariesLPw(pkg, pkgSetting, null, null, - combinedSigningDetails); - } catch (PackageManagerException e) { - Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e); - } - // Update all applications that use this library. Skip when booting - // since this will be done after all packages are scaned. - if ((scanFlags & SCAN_BOOTING) == 0) { - clientLibPkgs = mSharedLibraries.updateAllSharedLibrariesLPw(pkg, pkgSetting, - combinedSigningDetails); - } - } - } + ArrayList<AndroidPackage> clientLibPkgs = + mSharedLibraries.commitSharedLibraryChanges(pkg, pkgSetting, + reconciledPkg.mAllowedSharedLibraryInfos, + reconciledPkg.getCombinedAvailablePackages(), scanFlags); + if (reconciledPkg.mInstallResult != null) { reconciledPkg.mInstallResult.mLibraryConsumers = clientLibPkgs; } @@ -791,126 +781,14 @@ final class InstallPackageHelper { return false; } - public void processInstallRequests(boolean success, List<InstallRequest> installRequests) { - List<InstallRequest> apexInstallRequests = new ArrayList<>(); - List<InstallRequest> apkInstallRequests = new ArrayList<>(); - for (InstallRequest request : installRequests) { - if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) { - apexInstallRequests.add(request); - } else { - apkInstallRequests.add(request); - } - } - // Note: supporting multi package install of both APEXes and APKs might requir some - // thinking to ensure atomicity of the install. - if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) { - // This should've been caught at the validation step, but for some reason wasn't. - throw new IllegalStateException( - "Attempted to do a multi package install of both APEXes and APKs"); - } - if (!apexInstallRequests.isEmpty()) { - if (success) { - // Since installApexPackages requires talking to external service (apexd), we - // schedule to run it async. Once it finishes, it will resume the install. - Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests), - "installApexPackages"); - t.start(); - } else { - // Non-staged APEX installation failed somewhere before - // processInstallRequestAsync. In that case just notify the observer about the - // failure. - InstallRequest request = apexInstallRequests.get(0); - mPm.notifyInstallObserver(request.mInstallResult, - request.mArgs.mObserver); - } - return; - } - - processApkInstallRequests(success, installRequests); - } - - private void processApkInstallRequests(boolean success, List<InstallRequest> installRequests) { - if (success) { - for (InstallRequest request : installRequests) { - request.mArgs.doPreInstall(request.mInstallResult.mReturnCode); - } - synchronized (mPm.mInstallLock) { - installPackagesTracedLI(installRequests); - } - for (InstallRequest request : installRequests) { - request.mArgs.doPostInstall( - request.mInstallResult.mReturnCode, request.mInstallResult.mUid); - } - } - for (InstallRequest request : installRequests) { - restoreAndPostInstall(request.mArgs.mUser.getIdentifier(), - request.mInstallResult, - new PostInstallData(request.mArgs, - request.mInstallResult, null)); - } - } - - private void installApexPackagesTraced(List<InstallRequest> requests) { - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages"); - installApexPackages(requests); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - private void installApexPackages(List<InstallRequest> requests) { - if (requests.isEmpty()) { - return; - } - if (requests.size() != 1) { - throw new IllegalStateException( - "Only a non-staged install of a single APEX is supported"); - } - InstallRequest request = requests.get(0); - try { - // Should directory scanning logic be moved to ApexManager for better test coverage? - final File dir = request.mArgs.mOriginInfo.mResolvedFile; - final File[] apexes = dir.listFiles(); - if (apexes == null) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - dir.getAbsolutePath() + " is not a directory"); - } - if (apexes.length != 1) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Expected exactly one .apex file under " + dir.getAbsolutePath() - + " got: " + apexes.length); - } - try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) { - ApexInfo apexInfo = mApexManager.installPackage(apexes[0]); - if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) { - // APEX has been handled successfully by apexd. Let's continue the install flow - // so it will be scanned and registered with the system. - // TODO(b/225756739): Improve atomicity of rebootless APEX install. - // The newly installed APEX will not be reverted even if - // processApkInstallRequests() fails. Need a way to keep info stored in apexd - // and PMS in sync in the face of install failures. - request.mInstallResult.mApexInfo = apexInfo; - mPm.mHandler.post(() -> processApkInstallRequests(true, requests)); - return; - } else { - mPm.mApexPackageInfo.notifyPackageInstalled(apexInfo, packageParser); - } + void installPackagesTraced(List<InstallRequest> requests) { + synchronized (mPm.mInstallLock) { + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); + installPackagesLI(requests); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - } catch (PackageManagerException e) { - request.mInstallResult.setError("APEX installation failed", e); - } - PackageManagerService.invalidatePackageInfoCache(); - mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver); - } - - @GuardedBy("mPm.mInstallLock") - private void installPackagesTracedLI(List<InstallRequest> requests) { - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); - installPackagesLI(requests); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } @@ -1006,11 +884,12 @@ final class InstallPackageHelper { return; } } - ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs, - installResults, prepareResults, - Collections.unmodifiableMap(mPm.mPackages), versionInfos); - CommitRequest commitRequest = null; + + CommitRequest commitRequest; synchronized (mPm.mLock) { + ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs, + installResults, prepareResults, + Collections.unmodifiableMap(mPm.mPackages), versionInfos); Map<String, ReconciledPackage> reconciledPackages; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages"); @@ -1035,7 +914,7 @@ final class InstallPackageHelper { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } - executePostCommitSteps(commitRequest); + executePostCommitStepsLIF(commitRequest); } finally { if (success) { for (InstallRequest request : requests) { @@ -1057,7 +936,7 @@ final class InstallPackageHelper { .buildVerificationRootHashString(baseCodePath, splitCodePaths); VerificationUtils.broadcastPackageVerified(verificationId, originUri, PackageManager.VERIFICATION_ALLOW, rootHashString, - args.mDataLoaderType, args.getUser(), mContext); + args.mDataLoaderType, args.mUser, mContext); } } else { for (ScanResult result : preparedScans.values()) { @@ -1284,7 +1163,7 @@ final class InstallPackageHelper { // the package setting for the latest library version. if (parsedPackage.isStaticSharedLibrary()) { SharedLibraryInfo libraryInfo = - mSharedLibraries.getLatestStaticSharedLibraVersionLPr(parsedPackage); + mSharedLibraries.getLatestStaticSharedLibraVersion(parsedPackage); if (libraryInfo != null) { signatureCheckPs = mPm.mSettings.getPackageLPr(libraryInfo.getPackageName()); } @@ -1537,7 +1416,7 @@ final class InstallPackageHelper { } if (!isApex) { - if (!args.doRename(res.mReturnCode, parsedPackage)) { + if (!doRenameLI(args, res.mReturnCode, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); } @@ -1801,6 +1680,82 @@ final class InstallPackageHelper { } } + /** + * Rename package into final resting place. All paths on the given + * scanned package should be updated to reflect the rename. + */ + @GuardedBy("mPm.mInstallLock") + private boolean doRenameLI(InstallArgs args, int status, ParsedPackage parsedPackage) { + if (args.mMoveInfo != null) { + if (status != PackageManager.INSTALL_SUCCEEDED) { + mRemovePackageHelper.cleanUpForMoveInstall(args.mMoveInfo.mToUuid, + args.mMoveInfo.mPackageName, args.mMoveInfo.mFromCodePath); + return false; + } + return true; + } + // For file installations + if (status != PackageManager.INSTALL_SUCCEEDED) { + mRemovePackageHelper.removeCodePath(args.mCodeFile); + return false; + } + + final File targetDir = resolveTargetDir(args); + final File beforeCodeFile = args.mCodeFile; + final File afterCodeFile = PackageManagerServiceUtils.getNextCodePath(targetDir, + parsedPackage.getPackageName()); + + if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); + final boolean onIncremental = mPm.mIncrementalManager != null + && isIncrementalPath(beforeCodeFile.getAbsolutePath()); + try { + makeDirRecursive(afterCodeFile.getParentFile(), 0775); + if (onIncremental) { + // Just link files here. The stage dir will be removed when the installation + // session is completed. + mPm.mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile); + } else { + Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath()); + } + } catch (IOException | ErrnoException e) { + Slog.w(TAG, "Failed to rename", e); + return false; + } + + if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) { + Slog.w(TAG, "Failed to restorecon"); + return false; + } + + // Reflect the rename internally + args.mCodeFile = afterCodeFile; + + // Reflect the rename in scanned details + try { + parsedPackage.setPath(afterCodeFile.getCanonicalPath()); + } catch (IOException e) { + Slog.e(TAG, "Failed to get path: " + afterCodeFile, e); + return false; + } + parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile, + afterCodeFile, parsedPackage.getBaseApkPath())); + parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, + afterCodeFile, parsedPackage.getSplitCodePaths())); + + return true; + } + + // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged + // flow, we won't need this method anymore. + private File resolveTargetDir(InstallArgs args) { + boolean isStagedInstall = (args.mInstallFlags & INSTALL_STAGED) != 0; + if (isStagedInstall) { + return Environment.getDataAppDirectory(null); + } else { + return args.mCodeFile.getParentFile(); + } + } + /* * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges * as this only works for packages that are installed @@ -1898,7 +1853,6 @@ final class InstallPackageHelper { } } - final String packageName = pkg.getPackageName(); for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) { final String filePath = entry.getKey(); final String signaturePath = entry.getValue(); @@ -1969,12 +1923,12 @@ final class InstallPackageHelper { mPm.mSettings.getPackagesLocked()); if (reconciledPkg.mPrepareResult.mSystem) { // Remove existing system package - removePackageHelper.removePackageLI(oldPackage, true); + removePackageHelper.removePackage(oldPackage, true); if (!disableSystemPackageLPw(oldPackage)) { // We didn't need to disable the .apk as a current system package, // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. - res.mRemovedInfo.mArgs = new FileInstallArgs( + res.mRemovedInfo.mArgs = new InstallArgs( oldPackage.getPath(), getAppDexInstructionSets( AndroidPackageUtils.getPrimaryCpuAbi(oldPackage, @@ -1987,7 +1941,7 @@ final class InstallPackageHelper { } else { try { // Settings will be written during the call to updateSettingsLI(). - deletePackageHelper.executeDeletePackageLIF( + deletePackageHelper.executeDeletePackage( reconciledPkg.mDeletePackageAction, packageName, true, request.mAllUsers, false); } catch (SystemDeleteException e) { @@ -2257,7 +2211,8 @@ final class InstallPackageHelper { * is released. These are typically more expensive or require calls to installd, which often * locks on {@link com.android.server.pm.PackageManagerService.mLock}. */ - private void executePostCommitSteps(CommitRequest commitRequest) { + @GuardedBy("mPm.mInstallLock") + private void executePostCommitStepsLIF(CommitRequest commitRequest) { final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>(); for (ReconciledPackage reconciledPkg : commitRequest.mReconciledPackages.values()) { final boolean instantApp = ((reconciledPkg.mScanResult.mRequest.mScanFlags @@ -2648,9 +2603,7 @@ final class InstallPackageHelper { // Remove the update failed package's older resources safely now InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null; if (args != null) { - synchronized (mPm.mInstallLock) { - args.doPostDeleteLI(true); - } + mRemovePackageHelper.cleanUpResources(args); } mPm.notifyInstallObserver(res, installObserver); return; @@ -2888,9 +2841,7 @@ final class InstallPackageHelper { // ApplicationInfo changes have propagated to all application threads. mPm.scheduleDeferredNoKillPostDelete(args); } else { - synchronized (mPm.mInstallLock) { - args.doPostDeleteLI(true); - } + mRemovePackageHelper.cleanUpResources(args); } } else { // Force a gc to clear up things. Ask for a background one, it's fine to go on @@ -3024,7 +2975,7 @@ final class InstallPackageHelper { mAppDataHelper.prepareAppDataAfterInstallLIF(pkg); synchronized (mPm.mLock) { try { - mSharedLibraries.updateSharedLibrariesLPw( + mSharedLibraries.updateSharedLibraries( pkg, stubPkgSetting, null, null, Collections.unmodifiableMap(mPm.mPackages)); } catch (PackageManagerException e) { @@ -3096,14 +3047,14 @@ final class InstallPackageHelper { mPm.mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/); } final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm); - removePackageHelper.removePackageLI(stubPkg, true /*chatty*/); + removePackageHelper.removePackage(stubPkg, true /*chatty*/); try { return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(), e); // Remove the failed install - removePackageHelper.removeCodePathLI(scanFile); + removePackageHelper.removeCodePath(scanFile); throw e; } } @@ -3146,7 +3097,7 @@ final class InstallPackageHelper { if (!dstCodePath.exists()) { return null; } - new RemovePackageHelper(mPm).removeCodePathLI(dstCodePath); + new RemovePackageHelper(mPm).removeCodePath(dstCodePath); return null; } @@ -3232,16 +3183,16 @@ final class InstallPackageHelper { final AndroidPackage pkg = scanSystemPackageTracedLI( codePath, parseFlags, scanFlags, null); - PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName()); - - try { - // update shared libraries for the newly re-installed system package - mSharedLibraries.updateSharedLibrariesLPw(pkg, pkgSetting, null, null, - Collections.unmodifiableMap(mPm.mPackages)); - } catch (PackageManagerException e) { - Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); + synchronized (mPm.mLock) { + PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName()); + try { + // update shared libraries for the newly re-installed system package + mSharedLibraries.updateSharedLibraries(pkg, pkgSetting, null, null, + Collections.unmodifiableMap(mPm.mPackages)); + } catch (PackageManagerException e) { + Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); + } } - mAppDataHelper.prepareAppDataAfterInstallLIF(pkg); setPackageInstalledForSystemPackage(pkg, allUserHandles, origUserHandles, writeSettings); @@ -3344,7 +3295,7 @@ final class InstallPackageHelper { + ", versionCode=" + ps.getVersionCode() + "; scanned versionCode=" + scannedPkg.getLongVersionCode()); - mRemovePackageHelper.removePackageLI(scannedPkg, true); + mRemovePackageHelper.removePackage(scannedPkg, true); expectingBetter.put(ps.getPackageName(), ps.getPath()); } @@ -3354,7 +3305,7 @@ final class InstallPackageHelper { if (disabledPs == null) { logCriticalInfo(Log.WARN, "System package " + packageName + " no longer exists; its data will be wiped"); - mRemovePackageHelper.removePackageDataLIF(ps, userIds, null, 0, false); + mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false); } else { // we still have a disabled system package, but, it still might have // been removed. check the code path still exists and check there's @@ -3405,10 +3356,12 @@ final class InstallPackageHelper { // remove the package from the system and re-scan it without any // special privileges - mRemovePackageHelper.removePackageLI(pkg, true); + mRemovePackageHelper.removePackage(pkg, true); try { final File codePath = new File(pkg.getPath()); - scanSystemPackageTracedLI(codePath, 0, scanFlags, null); + synchronized (mPm.mInstallLock) { + scanSystemPackageTracedLI(codePath, 0, scanFlags, null); + } } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " + e.getMessage()); @@ -3421,7 +3374,7 @@ final class InstallPackageHelper { // partition], completely remove the package data. final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName); if (ps != null && mPm.mPackages.get(packageName) == null) { - mRemovePackageHelper.removePackageDataLIF(ps, userIds, null, 0, false); + mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false); } logCriticalInfo(Log.WARN, msg); } @@ -3581,7 +3534,7 @@ final class InstallPackageHelper { && errorCode != PackageManager.INSTALL_SUCCEEDED) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + parseResult.scanFile); - mRemovePackageHelper.removeCodePathLI(parseResult.scanFile); + mRemovePackageHelper.removeCodePath(parseResult.scanFile); } } } @@ -3617,11 +3570,13 @@ final class InstallPackageHelper { mPm.mSettings.enableSystemPackageLPw(packageName); try { - final AndroidPackage newPkg = scanSystemPackageTracedLI( - scanFile, reparseFlags, rescanFlags, null); - // We rescanned a stub, add it to the list of stubbed system packages - if (newPkg.isStub()) { - stubSystemApps.add(packageName); + synchronized (mPm.mInstallLock) { + final AndroidPackage newPkg = scanSystemPackageTracedLI( + scanFile, reparseFlags, rescanFlags, null); + // We rescanned a stub, add it to the list of stubbed system packages + if (newPkg.isStub()) { + stubSystemApps.add(packageName); + } } } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse original system package: " @@ -3634,7 +3589,7 @@ final class InstallPackageHelper { * Traces a package scan. * @see #scanSystemPackageLI(File, int, int, UserHandle) */ - @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) + @GuardedBy("mPm.mInstallLock") public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags, int scanFlags, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]"); @@ -3649,7 +3604,7 @@ final class InstallPackageHelper { * Scans a package and returns the newly parsed package. * Returns {@code null} in case of errors and the error code is stored in mLastScanError */ - @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) + @GuardedBy("mPm.mInstallLock") private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); @@ -3683,7 +3638,7 @@ final class InstallPackageHelper { * structures and the package is made available to the rest of the system. * <p>NOTE: The return value should be removed. It's the passed in package object. */ - @GuardedBy({"mPm.mLock", "mPm.mInstallLock"}) + @GuardedBy("mPm.mInstallLock") private AndroidPackage addForInitLI(ParsedPackage parsedPackage, @ParsingPackageUtils.ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, @@ -3765,11 +3720,13 @@ final class InstallPackageHelper { // iff we've acquired an app ID for a new package setting, remove it so that it can be // acquired by another request. if (result.mPkgSetting.getAppId() > 0) { - mPm.mSettings.removeAppIdLPw(result.mPkgSetting.getAppId()); + synchronized (mPm.mLock) { + mPm.mSettings.removeAppIdLPw(result.mPkgSetting.getAppId()); + } } } - @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) + @GuardedBy("mPm.mInstallLock") private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, final @ParsingPackageUtils.ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, long currentTime, @@ -3850,7 +3807,7 @@ final class InstallPackageHelper { realPkgName, parseFlags, scanFlags, isPlatformPackage, user, cpuAbiOverride); } - @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) + @GuardedBy("mPm.mInstallLock") private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage, final @ParsingPackageUtils.ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, long currentTime, @@ -3887,6 +3844,7 @@ final class InstallPackageHelper { } } + @GuardedBy("mPm.mInstallLock") private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage, @ParsingPackageUtils.ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, @@ -3969,10 +3927,10 @@ final class InstallPackageHelper { + "; " + pkgSetting.getPathString() + " --> " + parsedPackage.getPath()); - final InstallArgs args = new FileInstallArgs( + final InstallArgs args = new InstallArgs( pkgSetting.getPathString(), getAppDexInstructionSets( pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()), mPm); - args.cleanUpResourcesLI(); + mRemovePackageHelper.cleanUpResources(args); synchronized (mPm.mLock) { mPm.mSettings.enableSystemPackageLPw(pkgSetting.getPackageName()); } @@ -4054,13 +4012,11 @@ final class InstallPackageHelper { + parsedPackage.getLongVersionCode() + "; " + pkgSetting.getPathString() + " --> " + parsedPackage.getPath()); - InstallArgs args = new FileInstallArgs( + InstallArgs args = new InstallArgs( pkgSetting.getPathString(), getAppDexInstructionSets( pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()), mPm); - synchronized (mPm.mInstallLock) { - args.cleanUpResourcesLI(); - } + mRemovePackageHelper.cleanUpResources(args); } else { // The application on /system is older than the application on /data. Hide // the application on /system and the version on /data will be scanned later @@ -4085,7 +4041,6 @@ final class InstallPackageHelper { * Returns if forced apk verification can be skipped for the whole package, including splits. */ private boolean canSkipForcedPackageVerification(AndroidPackage pkg) { - final String packageName = pkg.getPackageName(); if (!VerityUtils.hasFsverity(pkg.getBaseApkPath())) { return false; } @@ -4392,8 +4347,10 @@ final class InstallPackageHelper { // signed with the platform certificate. Check this in increasing order of // computational cost. if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) { - final PackageSetting platformPkgSetting = - mPm.mSettings.getPackageLPr("android"); + final PackageSetting platformPkgSetting; + synchronized (mPm.mLock) { + platformPkgSetting = mPm.mSettings.getPackageLPr("android"); + } if (!comparePackageSignatures(platformPkgSetting, pkg.getSigningDetails().getSignatures())) { throw new PackageManagerException("Overlay " @@ -4411,8 +4368,10 @@ final class InstallPackageHelper { // SystemConfig is set, check this here to augment the last line of defense // which is OMS. if (pkg.getOverlayTargetOverlayableName() == null) { - final PackageSetting targetPkgSetting = - mPm.mSettings.getPackageLPr(pkg.getOverlayTarget()); + final PackageSetting targetPkgSetting; + synchronized (mPm.mLock) { + targetPkgSetting = mPm.mSettings.getPackageLPr(pkg.getOverlayTarget()); + } if (targetPkgSetting != null) { if (!comparePackageSignatures(targetPkgSetting, pkg.getSigningDetails().getSignatures())) { @@ -4424,9 +4383,11 @@ final class InstallPackageHelper { + " different certificates, and the overlay lacks" + " <overlay android:targetName>"); } - final PackageSetting refPkgSetting = - mPm.mSettings.getPackageLPr( - mPm.mOverlayConfigSignaturePackage); + final PackageSetting refPkgSetting; + synchronized (mPm.mLock) { + refPkgSetting = mPm.mSettings.getPackageLPr( + mPm.mOverlayConfigSignaturePackage); + } if (!comparePackageSignatures(refPkgSetting, pkg.getSigningDetails().getSignatures())) { throw new PackageManagerException("Overlay " @@ -4446,13 +4407,18 @@ final class InstallPackageHelper { if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) { SharedUserSetting sharedUserSetting = null; try { - sharedUserSetting = mPm.mSettings.getSharedUserLPw(pkg.getSharedUserId(), - 0, 0, false); + synchronized (mPm.mLock) { + sharedUserSetting = mPm.mSettings.getSharedUserLPw(pkg.getSharedUserId(), + 0, 0, false); + } } catch (PackageManagerException ignore) { } if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. - PackageSetting platformPkgSetting = mPm.mSettings.getPackageLPr("android"); + final PackageSetting platformPkgSetting; + synchronized (mPm.mLock) { + platformPkgSetting = mPm.mSettings.getPackageLPr("android"); + } if (!comparePackageSignatures(platformPkgSetting, pkg.getSigningDetails().getSignatures())) { throw new PackageManagerException("Apps that share a user with a " diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java index b3e039e5374b..0630ccdbf6e3 100644 --- a/services/core/java/com/android/server/pm/InstallingSession.java +++ b/services/core/java/com/android/server/pm/InstallingSession.java @@ -17,17 +17,21 @@ package com.android.server.pm; import static android.app.AppOpsManager.MODE_DEFAULT; +import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static android.os.incremental.IncrementalManager.isIncrementalPath; +import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT; import static com.android.server.pm.PackageManagerService.TAG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.apex.ApexInfo; import android.content.pm.DataLoaderType; import android.content.pm.IPackageInstallObserver2; import android.content.pm.PackageInfoLite; @@ -35,19 +39,28 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.SigningDetails; import android.content.pm.parsing.PackageLite; +import android.os.Environment; import android.os.Trace; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import com.android.internal.content.F2fsUtils; import com.android.internal.content.InstallLocationUtils; +import com.android.internal.content.NativeLibraryHelper; import com.android.internal.util.Preconditions; +import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.pkg.AndroidPackage; +import libcore.io.IoUtils; + import java.io.File; +import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; class InstallingSession { final OriginInfo mOriginInfo; @@ -79,6 +92,7 @@ class InstallingSession { @NonNull final PackageManagerService mPm; final InstallPackageHelper mInstallPackageHelper; + final RemovePackageHelper mRemovePackageHelper; InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer, int installFlags, InstallSource installSource, String volumeUuid, @@ -87,6 +101,7 @@ class InstallingSession { mPm = pm; mUser = user; mInstallPackageHelper = new InstallPackageHelper(mPm); + mRemovePackageHelper = new RemovePackageHelper(mPm); mOriginInfo = originInfo; mMoveInfo = moveInfo; mObserver = observer; @@ -115,6 +130,7 @@ class InstallingSession { mPm = pm; mUser = user; mInstallPackageHelper = new InstallPackageHelper(mPm); + mRemovePackageHelper = new RemovePackageHelper(mPm); mOriginInfo = OriginInfo.fromStagedFile(stagedDir); mMoveInfo = null; mInstallReason = fixUpInstallReason( @@ -195,7 +211,7 @@ class InstallingSession { * policy if needed and then create install arguments based * on the install location. */ - public void handleStartCopy() { + private void handleStartCopy() { if ((mInstallFlags & PackageManager.INSTALL_APEX) != 0) { mRet = INSTALL_SUCCEEDED; return; @@ -232,14 +248,14 @@ class InstallingSession { pkgLite.installLocation); } - void handleReturnCode() { + private void handleReturnCode() { processPendingInstall(); } private void processPendingInstall() { - InstallArgs args = createInstallArgs(this); + InstallArgs args = new InstallArgs(this); if (mRet == PackageManager.INSTALL_SUCCEEDED) { - mRet = args.copyApk(); + mRet = copyApk(args); } if (mRet == PackageManager.INSTALL_SUCCEEDED) { F2fsUtils.releaseCompressedBlocks( @@ -250,18 +266,89 @@ class InstallingSession { } else { PackageInstalledInfo res = new PackageInstalledInfo(mRet); // Queue up an async operation since the package installation may take a little while. - mPm.mHandler.post(() -> mInstallPackageHelper.processInstallRequests( + mPm.mHandler.post(() -> processInstallRequests( res.mReturnCode == PackageManager.INSTALL_SUCCEEDED /* success */, Collections.singletonList(new InstallRequest(args, res)))); } } - private InstallArgs createInstallArgs(InstallingSession installingSession) { - if (installingSession.mMoveInfo != null) { - return new MoveInstallArgs(installingSession); + private int copyApk(InstallArgs args) { + if (mMoveInfo == null) { + return copyApkForFileInstall(args); } else { - return new FileInstallArgs(installingSession); + return copyApkForMoveInstall(args); + } + } + + private int copyApkForFileInstall(InstallArgs args) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk"); + try { + if (mOriginInfo.mStaged) { + if (DEBUG_INSTALL) { + Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy"); + } + args.mCodeFile = mOriginInfo.mFile; + return PackageManager.INSTALL_SUCCEEDED; + } + + try { + final boolean isEphemeral = + (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0; + args.mCodeFile = + mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral); + } catch (IOException e) { + Slog.w(TAG, "Failed to create copy file: " + e); + return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } + + int ret = PackageManagerServiceUtils.copyPackage( + mOriginInfo.mFile.getAbsolutePath(), args.mCodeFile); + if (ret != PackageManager.INSTALL_SUCCEEDED) { + Slog.e(TAG, "Failed to copy package"); + return ret; + } + + final boolean isIncremental = isIncrementalPath(args.mCodeFile.getAbsolutePath()); + final File libraryRoot = new File(args.mCodeFile, LIB_DIR_NAME); + NativeLibraryHelper.Handle handle = null; + try { + handle = NativeLibraryHelper.Handle.create(args.mCodeFile); + ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, + args.mAbiOverride, isIncremental); + } catch (IOException e) { + Slog.e(TAG, "Copying native libraries failed", e); + ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + } finally { + IoUtils.closeQuietly(handle); + } + + return ret; + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + private int copyApkForMoveInstall(InstallArgs args) { + if (DEBUG_INSTALL) { + Slog.d(TAG, "Moving " + mMoveInfo.mPackageName + " from " + + mMoveInfo.mFromUuid + " to " + mMoveInfo.mToUuid); } + synchronized (mPm.mInstallLock) { + try { + mPm.mInstaller.moveCompleteApp(mMoveInfo.mFromUuid, mMoveInfo.mToUuid, + mMoveInfo.mPackageName, mMoveInfo.mAppId, mMoveInfo.mSeInfo, + mMoveInfo.mTargetSdkVersion, mMoveInfo.mFromCodePath); + } catch (Installer.InstallerException e) { + Slog.w(TAG, "Failed to move app", e); + return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + } + } + + final String toPathName = new File(mMoveInfo.mFromCodePath).getName(); + args.mCodeFile = new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName); + if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + args.mCodeFile); + + return PackageManager.INSTALL_SUCCEEDED; } /** @@ -368,4 +455,217 @@ class InstallingSession { private void setTraceCookie(int traceCookie) { mTraceCookie = traceCookie; } + + private void processInstallRequests(boolean success, List<InstallRequest> installRequests) { + List<InstallRequest> apexInstallRequests = new ArrayList<>(); + List<InstallRequest> apkInstallRequests = new ArrayList<>(); + for (InstallRequest request : installRequests) { + if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) { + apexInstallRequests.add(request); + } else { + apkInstallRequests.add(request); + } + } + // Note: supporting multi package install of both APEXes and APKs might requir some + // thinking to ensure atomicity of the install. + if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) { + // This should've been caught at the validation step, but for some reason wasn't. + throw new IllegalStateException( + "Attempted to do a multi package install of both APEXes and APKs"); + } + if (!apexInstallRequests.isEmpty()) { + if (success) { + // Since installApexPackages requires talking to external service (apexd), we + // schedule to run it async. Once it finishes, it will resume the install. + Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests), + "installApexPackages"); + t.start(); + } else { + // Non-staged APEX installation failed somewhere before + // processInstallRequestAsync. In that case just notify the observer about the + // failure. + InstallRequest request = apexInstallRequests.get(0); + mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver); + } + return; + } + + processApkInstallRequests(success, installRequests); + } + + private void processApkInstallRequests(boolean success, List<InstallRequest> installRequests) { + if (success) { + for (InstallRequest request : installRequests) { + if (request.mInstallResult.mReturnCode != PackageManager.INSTALL_SUCCEEDED) { + cleanUpForFailedInstall(request.mArgs); + } + } + + mInstallPackageHelper.installPackagesTraced(installRequests); + + for (InstallRequest request : installRequests) { + doPostInstall(request.mInstallResult.mReturnCode, request.mArgs); + } + } + for (InstallRequest request : installRequests) { + mInstallPackageHelper.restoreAndPostInstall(request.mArgs.mUser.getIdentifier(), + request.mInstallResult, + new PostInstallData(request.mArgs, + request.mInstallResult, null)); + } + } + + private void doPostInstall(int status, InstallArgs args) { + if (mMoveInfo != null) { + if (status == PackageManager.INSTALL_SUCCEEDED) { + mRemovePackageHelper.cleanUpForMoveInstall(mMoveInfo.mFromUuid, + mMoveInfo.mPackageName, mMoveInfo.mFromCodePath); + } else { + mRemovePackageHelper.cleanUpForMoveInstall(mMoveInfo.mToUuid, + mMoveInfo.mPackageName, mMoveInfo.mFromCodePath); + } + } else { + if (status != PackageManager.INSTALL_SUCCEEDED) { + mRemovePackageHelper.removeCodePath(args.mCodeFile); + } + } + } + + private void cleanUpForFailedInstall(InstallArgs args) { + if (args.mMoveInfo != null) { + mRemovePackageHelper.cleanUpForMoveInstall(args.mMoveInfo.mToUuid, + args.mMoveInfo.mPackageName, args.mMoveInfo.mFromCodePath); + } else { + mRemovePackageHelper.removeCodePath(args.mCodeFile); + } + } + + private void installApexPackagesTraced(List<InstallRequest> requests) { + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages"); + installApexPackages(requests); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + private void installApexPackages(List<InstallRequest> requests) { + if (requests.isEmpty()) { + return; + } + if (requests.size() != 1) { + throw new IllegalStateException( + "Only a non-staged install of a single APEX is supported"); + } + InstallRequest request = requests.get(0); + try { + // Should directory scanning logic be moved to ApexManager for better test coverage? + final File dir = request.mArgs.mOriginInfo.mResolvedFile; + final File[] apexes = dir.listFiles(); + if (apexes == null) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + dir.getAbsolutePath() + " is not a directory"); + } + if (apexes.length != 1) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Expected exactly one .apex file under " + dir.getAbsolutePath() + + " got: " + apexes.length); + } + try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) { + ApexInfo apexInfo = mPm.mApexManager.installPackage(apexes[0]); + if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) { + // APEX has been handled successfully by apexd. Let's continue the install flow + // so it will be scanned and registered with the system. + // TODO(b/225756739): Improve atomicity of rebootless APEX install. + // The newly installed APEX will not be reverted even if + // processApkInstallRequests() fails. Need a way to keep info stored in apexd + // and PMS in sync in the face of install failures. + request.mInstallResult.mApexInfo = apexInfo; + mPm.mHandler.post(() -> processApkInstallRequests(true, requests)); + return; + } else { + mPm.mApexPackageInfo.notifyPackageInstalled(apexInfo, packageParser); + } + } + } catch (PackageManagerException e) { + request.mInstallResult.setError("APEX installation failed", e); + } + PackageManagerService.invalidatePackageInfoCache(); + mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver); + } + + /** + * Container for a multi-package install which refers to all install sessions and args being + * committed together. + */ + private class MultiPackageInstallingSession { + private final List<InstallingSession> mChildInstallingSessions; + private final Map<InstallArgs, Integer> mCurrentState; + @NonNull + final PackageManagerService mPm; + final UserHandle mUser; + + MultiPackageInstallingSession(UserHandle user, + List<InstallingSession> childInstallingSessions, + PackageManagerService pm) + throws PackageManagerException { + if (childInstallingSessions.size() == 0) { + throw new PackageManagerException("No child sessions found!"); + } + mPm = pm; + mUser = user; + mChildInstallingSessions = childInstallingSessions; + for (int i = 0; i < childInstallingSessions.size(); i++) { + final InstallingSession childInstallingSession = childInstallingSessions.get(i); + childInstallingSession.mParentInstallingSession = this; + } + this.mCurrentState = new ArrayMap<>(mChildInstallingSessions.size()); + } + + public void start() { + if (DEBUG_INSTALL) Slog.i(TAG, "start " + mUser + ": " + this); + Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", + System.identityHashCode(this)); + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "start"); + for (InstallingSession childInstallingSession : mChildInstallingSessions) { + childInstallingSession.handleStartCopy(); + } + for (InstallingSession childInstallingSession : mChildInstallingSessions) { + childInstallingSession.handleReturnCode(); + } + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + + public void tryProcessInstallRequest(InstallArgs args, int currentStatus) { + mCurrentState.put(args, currentStatus); + if (mCurrentState.size() != mChildInstallingSessions.size()) { + return; + } + int completeStatus = PackageManager.INSTALL_SUCCEEDED; + for (Integer status : mCurrentState.values()) { + if (status == PackageManager.INSTALL_UNKNOWN) { + return; + } else if (status != PackageManager.INSTALL_SUCCEEDED) { + completeStatus = status; + break; + } + } + final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size()); + for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) { + installRequests.add(new InstallRequest(entry.getKey(), + new PackageInstalledInfo(completeStatus))); + } + int finalCompleteStatus = completeStatus; + mPm.mHandler.post(() -> processInstallRequests( + finalCompleteStatus == PackageManager.INSTALL_SUCCEEDED /* success */, + installRequests)); + } + + @Override + public String toString() { + return "MultiPackageInstallingSession{" + Integer.toHexString( + System.identityHashCode(this)) + + "}"; + } + } } diff --git a/services/core/java/com/android/server/pm/MoveInstallArgs.java b/services/core/java/com/android/server/pm/MoveInstallArgs.java deleted file mode 100644 index 1f167ce2ec9a..000000000000 --- a/services/core/java/com/android/server/pm/MoveInstallArgs.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm; - -import static android.os.storage.StorageManager.FLAG_STORAGE_CE; -import static android.os.storage.StorageManager.FLAG_STORAGE_DE; - -import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; -import static com.android.server.pm.PackageManagerService.TAG; - -import android.content.pm.PackageManager; -import android.os.Environment; -import android.util.Slog; - -import com.android.server.pm.parsing.pkg.ParsedPackage; - -import java.io.File; - -/** - * Logic to handle movement of existing installed applications. - */ -final class MoveInstallArgs extends InstallArgs { - private File mCodeFile; - - /** New install */ - MoveInstallArgs(InstallingSession params) { - super(params); - } - - int copyApk() { - if (DEBUG_INSTALL) { - Slog.d(TAG, "Moving " + mMoveInfo.mPackageName + " from " - + mMoveInfo.mFromUuid + " to " + mMoveInfo.mToUuid); - } - synchronized (mPm.mInstaller) { - try { - mPm.mInstaller.moveCompleteApp(mMoveInfo.mFromUuid, mMoveInfo.mToUuid, - mMoveInfo.mPackageName, mMoveInfo.mAppId, mMoveInfo.mSeInfo, - mMoveInfo.mTargetSdkVersion, mMoveInfo.mFromCodePath); - } catch (Installer.InstallerException e) { - Slog.w(TAG, "Failed to move app", e); - return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; - } - } - - final String toPathName = new File(mMoveInfo.mFromCodePath).getName(); - mCodeFile = new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName); - if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + mCodeFile); - - return PackageManager.INSTALL_SUCCEEDED; - } - - int doPreInstall(int status) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(mMoveInfo.mToUuid); - } - return status; - } - - @Override - boolean doRename(int status, ParsedPackage parsedPackage) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(mMoveInfo.mToUuid); - return false; - } - - return true; - } - - int doPostInstall(int status, int uid) { - if (status == PackageManager.INSTALL_SUCCEEDED) { - cleanUp(mMoveInfo.mFromUuid); - } else { - cleanUp(mMoveInfo.mToUuid); - } - return status; - } - - @Override - String getCodePath() { - return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null; - } - - private void cleanUp(String volumeUuid) { - final String toPathName = new File(mMoveInfo.mFromCodePath).getName(); - final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid), - toPathName); - Slog.d(TAG, "Cleaning up " + mMoveInfo.mPackageName + " on " + volumeUuid); - final int[] userIds = mPm.mUserManager.getUserIds(); - synchronized (mPm.mInstallLock) { - // Clean up both app data and code - // All package moves are frozen until finished - - // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since - // this task was only focused on moving data on internal storage. - // We don't want ART profiles cleared, because they don't move, - // so we would be deleting the only copy (b/149200535). - final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE - | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES; - for (int userId : userIds) { - try { - mPm.mInstaller.destroyAppData(volumeUuid, mMoveInfo.mPackageName, userId, flags, - 0); - } catch (Installer.InstallerException e) { - Slog.w(TAG, String.valueOf(e)); - } - } - mRemovePackageHelper.removeCodePathLI(codeFile); - } - } - - void cleanUpResourcesLI() { - throw new UnsupportedOperationException(); - } - - boolean doPostDeleteLI(boolean delete) { - throw new UnsupportedOperationException(); - } -} diff --git a/services/core/java/com/android/server/pm/MultiPackageInstallingSession.java b/services/core/java/com/android/server/pm/MultiPackageInstallingSession.java deleted file mode 100644 index e5ed5d8a5f5b..000000000000 --- a/services/core/java/com/android/server/pm/MultiPackageInstallingSession.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm; - -import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; - -import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; -import static com.android.server.pm.PackageManagerService.TAG; - -import android.annotation.NonNull; -import android.content.pm.PackageManager; -import android.os.Trace; -import android.os.UserHandle; -import android.util.ArrayMap; -import android.util.Slog; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Container for a multi-package install which refers to all install sessions and args being - * committed together. - */ -final class MultiPackageInstallingSession { - private final List<InstallingSession> mChildInstallingSessions; - private final Map<InstallArgs, Integer> mCurrentState; - @NonNull - final PackageManagerService mPm; - final UserHandle mUser; - - MultiPackageInstallingSession(UserHandle user, List<InstallingSession> childInstallingSessions, - PackageManagerService pm) - throws PackageManagerException { - if (childInstallingSessions.size() == 0) { - throw new PackageManagerException("No child sessions found!"); - } - mPm = pm; - mUser = user; - mChildInstallingSessions = childInstallingSessions; - for (int i = 0; i < childInstallingSessions.size(); i++) { - final InstallingSession childInstallingSession = childInstallingSessions.get(i); - childInstallingSession.mParentInstallingSession = this; - } - this.mCurrentState = new ArrayMap<>(mChildInstallingSessions.size()); - } - - public void start() { - if (DEBUG_INSTALL) Slog.i(TAG, "start " + mUser + ": " + this); - Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", - System.identityHashCode(this)); - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "start"); - for (InstallingSession childInstallingSession : mChildInstallingSessions) { - childInstallingSession.handleStartCopy(); - } - for (InstallingSession childInstallingSession : mChildInstallingSessions) { - childInstallingSession.handleReturnCode(); - } - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - - public void tryProcessInstallRequest(InstallArgs args, int currentStatus) { - mCurrentState.put(args, currentStatus); - if (mCurrentState.size() != mChildInstallingSessions.size()) { - return; - } - int completeStatus = PackageManager.INSTALL_SUCCEEDED; - for (Integer status : mCurrentState.values()) { - if (status == PackageManager.INSTALL_UNKNOWN) { - return; - } else if (status != PackageManager.INSTALL_SUCCEEDED) { - completeStatus = status; - break; - } - } - final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size()); - for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) { - installRequests.add(new InstallRequest(entry.getKey(), - new PackageInstalledInfo(completeStatus))); - } - int finalCompleteStatus = completeStatus; - final InstallPackageHelper installPackageHelper = new InstallPackageHelper(mPm); - mPm.mHandler.post(() -> installPackageHelper.processInstallRequests( - finalCompleteStatus == PackageManager.INSTALL_SUCCEEDED /* success */, - installRequests)); - } - - @Override - public String toString() { - return "MultiPackageInstallingSession{" + Integer.toHexString(System.identityHashCode(this)) - + "}"; - } -} diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java index c950dcfc30bd..d50e55ee5303 100644 --- a/services/core/java/com/android/server/pm/PackageHandler.java +++ b/services/core/java/com/android/server/pm/PackageHandler.java @@ -62,11 +62,13 @@ import java.io.IOException; final class PackageHandler extends Handler { private final PackageManagerService mPm; private final InstallPackageHelper mInstallPackageHelper; + private final RemovePackageHelper mRemovePackageHelper; PackageHandler(Looper looper, PackageManagerService pm) { super(looper); mPm = pm; mInstallPackageHelper = new InstallPackageHelper(mPm); + mRemovePackageHelper = new RemovePackageHelper(mPm); } @Override @@ -107,11 +109,9 @@ final class PackageHandler extends Handler { Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1); } break; case DEFERRED_NO_KILL_POST_DELETE: { - synchronized (mPm.mInstallLock) { - InstallArgs args = (InstallArgs) msg.obj; - if (args != null) { - args.doPostDeleteLI(true); - } + InstallArgs args = (InstallArgs) msg.obj; + if (args != null) { + mRemovePackageHelper.cleanUpResources(args); } } break; case DEFERRED_NO_KILL_INSTALL_OBSERVER: diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index bb23d89d218f..6ee43a0268b6 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -379,9 +379,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // Clean up orphaned staging directories for (File stage : stagingDirsToRemove) { Slog.w(TAG, "Deleting orphan stage " + stage); - synchronized (mPm.mInstallLock) { - removePackageHelper.removeCodePathLI(stage); - } + removePackageHelper.removeCodePath(stage); } } diff --git a/services/core/java/com/android/server/pm/ReconciledPackage.java b/services/core/java/com/android/server/pm/ReconciledPackage.java index bd63a1a4f10f..1bfe3576225f 100644 --- a/services/core/java/com/android/server/pm/ReconciledPackage.java +++ b/services/core/java/com/android/server/pm/ReconciledPackage.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.SharedLibraryInfo; import android.content.pm.SigningDetails; @@ -75,7 +76,7 @@ final class ReconciledPackage { * with the package(s) currently being installed. The to-be installed packages take * precedence and may shadow already installed packages. */ - Map<String, AndroidPackage> getCombinedAvailablePackages() { + @NonNull Map<String, AndroidPackage> getCombinedAvailablePackages() { final ArrayMap<String, AndroidPackage> combined = new ArrayMap<>(mRequest.mAllPackages.size() + mRequest.mScannedPackages.size()); diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java index 65d3430fe474..f083b67a0402 100644 --- a/services/core/java/com/android/server/pm/RemovePackageHelper.java +++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java @@ -23,6 +23,7 @@ import static android.os.storage.StorageManager.FLAG_STORAGE_CE; import static android.os.storage.StorageManager.FLAG_STORAGE_DE; import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL; +import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; import static com.android.server.pm.PackageManagerService.RANDOM_DIR_PREFIX; @@ -30,6 +31,11 @@ import static com.android.server.pm.PackageManagerService.TAG; import android.annotation.NonNull; import android.content.pm.PackageManager; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; +import android.os.Environment; import android.os.Trace; import android.os.UserHandle; import android.os.incremental.IncrementalManager; @@ -78,8 +84,17 @@ final class RemovePackageHelper { this(pm, new AppDataHelper(pm)); } + public void removeCodePath(File codePath) { + synchronized (mPm.mInstallLock) { + removeCodePathLI(codePath); + } + } + @GuardedBy("mPm.mInstallLock") - public void removeCodePathLI(File codePath) { + private void removeCodePathLI(File codePath) { + if (codePath == null || !codePath.exists()) { + return; + } if (codePath.isDirectory()) { final File codePathParent = codePath.getParentFile(); final boolean needRemoveParent = codePathParent.getName().startsWith(RANDOM_DIR_PREFIX); @@ -118,7 +133,14 @@ final class RemovePackageHelper { cacher.cleanCachedResult(codePath); } - public void removePackageLI(AndroidPackage pkg, boolean chatty) { + public void removePackage(AndroidPackage pkg, boolean chatty) { + synchronized (mPm.mInstallLock) { + removePackageLI(pkg, chatty); + } + } + + @GuardedBy("mPm.mInstallLock") + private void removePackageLI(AndroidPackage pkg, boolean chatty) { // Remove the parent package setting PackageStateInternal ps = mPm.snapshotComputer() .getPackageStateInternal(pkg.getPackageName()); @@ -129,6 +151,7 @@ final class RemovePackageHelper { } } + @GuardedBy("mPm.mInstallLock") private void removePackageLI(String packageName, boolean chatty) { if (DEBUG_INSTALL) { if (chatty) { @@ -145,6 +168,7 @@ final class RemovePackageHelper { } } + @GuardedBy("mPm.mLock") private void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mPm.mComponentResolver.removeAllComponents(pkg, chatty); mPermissionManager.onPackageRemoved(pkg); @@ -175,7 +199,7 @@ final class RemovePackageHelper { final int libraryNamesSize = pkg.getLibraryNames().size(); for (i = 0; i < libraryNamesSize; i++) { String name = pkg.getLibraryNames().get(i); - if (mSharedLibraries.removeSharedLibraryLPw(name, 0)) { + if (mSharedLibraries.removeSharedLibrary(name, 0)) { if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); @@ -192,7 +216,7 @@ final class RemovePackageHelper { // Any package can hold SDK or static shared libraries. if (pkg.getSdkLibName() != null) { - if (mSharedLibraries.removeSharedLibraryLPw( + if (mSharedLibraries.removeSharedLibrary( pkg.getSdkLibName(), pkg.getSdkLibVersionMajor())) { if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -205,7 +229,7 @@ final class RemovePackageHelper { } } if (pkg.getStaticSharedLibName() != null) { - if (mSharedLibraries.removeSharedLibraryLPw(pkg.getStaticSharedLibName(), + if (mSharedLibraries.removeSharedLibrary(pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion())) { if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -223,12 +247,20 @@ final class RemovePackageHelper { } } + public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles, + PackageRemovedInfo outInfo, int flags, boolean writeSettings) { + synchronized (mPm.mInstallLock) { + removePackageDataLIF(deletedPs, allUserHandles, outInfo, flags, writeSettings); + } + } + /* * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA * flag is not set, the data directory is removed as well. * make sure this flag is set for partially installed apps. If not its meaningless to * delete a partially installed application. */ + @GuardedBy("mPm.mInstallLock") public void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles, PackageRemovedInfo outInfo, int flags, boolean writeSettings) { String packageName = deletedPs.getPackageName(); @@ -352,4 +384,74 @@ final class RemovePackageHelper { }); } } + + void cleanUpResources(InstallArgs args) { + synchronized (mPm.mInstallLock) { + cleanUpResourcesLI(args); + } + } + + // Need installer lock especially for dex file removal. + @GuardedBy("mPm.mInstallLock") + private void cleanUpResourcesLI(InstallArgs args) { + // Try enumerating all code paths before deleting + List<String> allCodePaths = Collections.EMPTY_LIST; + if (args.mCodeFile != null && args.mCodeFile.exists()) { + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( + input.reset(), args.mCodeFile, /* flags */ 0); + if (result.isSuccess()) { + // Ignore error; we tried our best + allCodePaths = result.getResult().getAllApkPaths(); + } + } + + removeCodePathLI(args.mCodeFile); + removeDexFilesLI(allCodePaths, args.mInstructionSets); + } + + @GuardedBy("mPm.mInstallLock") + private void removeDexFilesLI(List<String> allCodePaths, String[] instructionSets) { + if (!allCodePaths.isEmpty()) { + if (instructionSets == null) { + throw new IllegalStateException("instructionSet == null"); + } + String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); + for (String codePath : allCodePaths) { + for (String dexCodeInstructionSet : dexCodeInstructionSets) { + try { + mPm.mInstaller.rmdex(codePath, dexCodeInstructionSet); + } catch (Installer.InstallerException ignored) { + } + } + } + } + } + + void cleanUpForMoveInstall(String volumeUuid, String packageName, String fromCodePath) { + final String toPathName = new File(fromCodePath).getName(); + final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid), toPathName); + Slog.d(TAG, "Cleaning up " + packageName + " on " + volumeUuid); + final int[] userIds = mPm.mUserManager.getUserIds(); + synchronized (mPm.mInstallLock) { + // Clean up both app data and code + // All package moves are frozen until finished + + // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since + // this task was only focused on moving data on internal storage. + // We don't want ART profiles cleared, because they don't move, + // so we would be deleting the only copy (b/149200535). + final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE + | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES; + for (int userId : userIds) { + try { + mPm.mInstaller.destroyAppData(volumeUuid, packageName, userId, flags, + 0); + } catch (Installer.InstallerException e) { + Slog.w(TAG, String.valueOf(e)); + } + } + removeCodePathLI(codeFile); + } + } } diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java index 479a404c88bf..7432b8446f35 100644 --- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java +++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java @@ -19,6 +19,7 @@ package com.android.server.pm; import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; +import static com.android.server.pm.PackageManagerService.SCAN_BOOTING; import static com.android.server.pm.PackageManagerService.TAG; import android.annotation.NonNull; @@ -258,11 +259,13 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable * Given the library name, returns a list of shared libraries on all versions. * TODO: Remove, this is used for live mutation outside of the defined commit path */ - @GuardedBy("mPm.mLock") + @Override public @NonNull WatchedLongSparseArray<SharedLibraryInfo> getSharedLibraryInfos( @NonNull String libName) { - return mSharedLibraries.get(libName); + synchronized (mPm.mLock) { + return mSharedLibraries.get(libName); + } } @VisibleForTesting @@ -381,6 +384,11 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable return false; } + @Nullable SharedLibraryInfo getLatestStaticSharedLibraVersion(@NonNull AndroidPackage pkg) { + synchronized (mPm.mLock) { + return getLatestStaticSharedLibraVersionLPr(pkg); + } + } /** * Given a package of static shared library, returns its shared library info of * the latest version. @@ -389,7 +397,8 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable * @return The latest version of shared library info. */ @GuardedBy("mPm.mLock") - @Nullable SharedLibraryInfo getLatestStaticSharedLibraVersionLPr(@NonNull AndroidPackage pkg) { + @Nullable + private SharedLibraryInfo getLatestStaticSharedLibraVersionLPr(@NonNull AndroidPackage pkg) { WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get( pkg.getStaticSharedLibName()); if (versionedLib == null) { @@ -524,15 +533,26 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable * @param changingLibSetting The updating library package setting. * @param availablePackages All installed packages and current being installed packages. */ - @GuardedBy("mPm.mLock") - void updateSharedLibrariesLPw(@NonNull AndroidPackage pkg, @NonNull PackageSetting pkgSetting, + void updateSharedLibraries(@NonNull AndroidPackage pkg, @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting, @NonNull Map<String, AndroidPackage> availablePackages) throws PackageManagerException { final ArrayList<SharedLibraryInfo> sharedLibraryInfos = collectSharedLibraryInfos( pkg, availablePackages, null /* newLibraries */); - executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting, - sharedLibraryInfos, mPm.mUserManager.getUserIds()); + synchronized (mPm.mLock) { + executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting, + sharedLibraryInfos, mPm.mUserManager.getUserIds()); + } + } + + void executeSharedLibrariesUpdate(AndroidPackage pkg, + @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib, + @Nullable PackageSetting changingLibSetting, + ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) { + synchronized (mPm.mLock) { + executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting, + usesLibraryInfos, allUsers); + } } /** @@ -547,7 +567,7 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable * @param allUsers All user ids on the device. */ @GuardedBy("mPm.mLock") - void executeSharedLibrariesUpdateLPw(AndroidPackage pkg, + private void executeSharedLibrariesUpdateLPw(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting, ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) { @@ -610,6 +630,31 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable return false; } + ArrayList<AndroidPackage> commitSharedLibraryChanges(@NonNull AndroidPackage pkg, + @NonNull PackageSetting pkgSetting, List<SharedLibraryInfo> allowedSharedLibraryInfos, + @NonNull Map<String, AndroidPackage> combinedSigningDetails, int scanFlags) { + if (ArrayUtils.isEmpty(allowedSharedLibraryInfos)) { + return null; + } + synchronized (mPm.mLock) { + for (SharedLibraryInfo info : allowedSharedLibraryInfos) { + commitSharedLibraryInfoLPw(info); + } + try { + // Shared libraries for the package need to be updated. + updateSharedLibraries(pkg, pkgSetting, null, null, combinedSigningDetails); + } catch (PackageManagerException e) { + Slog.e(TAG, "updateSharedLibraries failed: ", e); + } + // Update all applications that use this library. Skip when booting + // since this will be done after all packages are scaned. + if ((scanFlags & SCAN_BOOTING) == 0) { + return updateAllSharedLibrariesLPw(pkg, pkgSetting, combinedSigningDetails); + } + } + return null; + } + /** * Update shared library dependencies and code paths for applications that are using the * library {@code updatedPkg}. Update all applications if the {@code updatedPkg} is null. @@ -666,7 +711,7 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable } } try { - updateSharedLibrariesLPw(pkg, pkgSetting, changingPkg, + updateSharedLibraries(pkg, pkgSetting, changingPkg, changingPkgSetting, availablePackages); } catch (PackageManagerException e) { // If a system app update or an app and a required lib missing we @@ -677,9 +722,11 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) { final int flags = pkgSetting.getPkgState().isUpdatedSystemApp() ? PackageManager.DELETE_KEEP_DATA : 0; - mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true, - mPm.mUserManager.getUserIds(), flags, null, - true); + synchronized (mPm.mInstallLock) { + mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true, + mPm.mUserManager.getUserIds(), flags, null, + true); + } } Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } @@ -711,6 +758,7 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable * Add a shared library info to the system. This is invoked when the package is being added or * scanned. */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @GuardedBy("mPm.mLock") void commitSharedLibraryInfoLPw(@NonNull SharedLibraryInfo libraryInfo) { final String name = libraryInfo.getName(); @@ -729,45 +777,46 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable /** * Remove a shared library from the system. */ - @GuardedBy("mPm.mLock") - boolean removeSharedLibraryLPw(@NonNull String libName, long version) { - WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName); - if (versionedLib == null) { - return false; - } - final int libIdx = versionedLib.indexOfKey(version); - if (libIdx < 0) { - return false; - } - SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx); + boolean removeSharedLibrary(@NonNull String libName, long version) { + synchronized (mPm.mLock) { + WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName); + if (versionedLib == null) { + return false; + } + final int libIdx = versionedLib.indexOfKey(version); + if (libIdx < 0) { + return false; + } + SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx); - final Computer snapshot = mPm.snapshotComputer(); + final Computer snapshot = mPm.snapshotComputer(); - // Remove the shared library overlays from its dependent packages. - for (int currentUserId : mPm.mUserManager.getUserIds()) { - final List<VersionedPackage> dependents = snapshot.getPackagesUsingSharedLibrary( - libraryInfo, 0, Process.SYSTEM_UID, currentUserId); - if (dependents == null) { - continue; - } - for (VersionedPackage dependentPackage : dependents) { - final PackageSetting ps = mPm.mSettings.getPackageLPr( - dependentPackage.getPackageName()); - if (ps != null) { - ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId); + // Remove the shared library overlays from its dependent packages. + for (int currentUserId : mPm.mUserManager.getUserIds()) { + final List<VersionedPackage> dependents = snapshot.getPackagesUsingSharedLibrary( + libraryInfo, 0, Process.SYSTEM_UID, currentUserId); + if (dependents == null) { + continue; + } + for (VersionedPackage dependentPackage : dependents) { + final PackageSetting ps = mPm.mSettings.getPackageLPr( + dependentPackage.getPackageName()); + if (ps != null) { + ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId); + } } } - } - versionedLib.remove(version); - if (versionedLib.size() <= 0) { - mSharedLibraries.remove(libName); - if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) { - mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage() - .getPackageName()); + versionedLib.remove(version); + if (versionedLib.size() <= 0) { + mSharedLibraries.remove(libName); + if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) { + mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage() + .getPackageName()); + } } + return true; } - return true; } /** diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java index fe1c83bab30c..f621d8b2533a 100644 --- a/services/core/java/com/android/server/pm/StorageEventHelper.java +++ b/services/core/java/com/android/server/pm/StorageEventHelper.java @@ -346,9 +346,7 @@ public final class StorageEventHelper extends StorageEventListener { for (int i = 0; i < fileToDeleteCount; i++) { File fileToDelete = filesToDelete.get(i); logCriticalInfo(Log.WARN, "Destroying orphaned at " + fileToDelete); - synchronized (mPm.mInstallLock) { - mRemovePackageHelper.removeCodePathLI(fileToDelete); - } + mRemovePackageHelper.removeCodePath(fileToDelete); } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt index b42a3b0719df..e59a404ebed4 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt @@ -39,6 +39,10 @@ import com.android.server.testutils.spy import com.android.server.testutils.whenever import com.android.server.utils.WatchedLongSparseArray import com.google.common.truth.Truth.assertThat +import java.io.File +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue import libcore.util.HexEncoding import org.junit.Before import org.junit.Rule @@ -51,10 +55,6 @@ import org.mockito.Mock import org.mockito.Mockito.doAnswer import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations -import java.io.File -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse -import kotlin.test.assertTrue @RunWith(JUnit4::class) class SharedLibrariesImplTest { @@ -186,7 +186,7 @@ class SharedLibrariesImplTest { val staticInfo = mSharedLibrariesImpl .getSharedLibraryInfo(STATIC_LIB_NAME, STATIC_LIB_VERSION)!! - mSharedLibrariesImpl.removeSharedLibraryLPw(STATIC_LIB_NAME, STATIC_LIB_VERSION) + mSharedLibrariesImpl.removeSharedLibrary(STATIC_LIB_NAME, STATIC_LIB_VERSION) assertThat(mSharedLibrariesImpl.getSharedLibraryInfos(STATIC_LIB_NAME)).isNull() assertThat(mSharedLibrariesImpl @@ -208,7 +208,7 @@ class SharedLibrariesImplTest { staticLibrary = STATIC_LIB_NAME, staticLibraryVersion = 10L) val latestInfo = - mSharedLibrariesImpl.getLatestStaticSharedLibraVersionLPr(pair.second)!! + mSharedLibrariesImpl.getLatestStaticSharedLibraVersion(pair.second)!! assertThat(latestInfo).isNotNull() assertThat(latestInfo.name).isEqualTo(STATIC_LIB_NAME) @@ -237,7 +237,7 @@ class SharedLibrariesImplTest { testPackageSetting.setPkgStateLibraryFiles(listOf()) assertThat(testPackageSetting.usesLibraryFiles).isEmpty() - mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting, + mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg, testPackageSetting, null /* changingLib */, null /* changingLibSetting */, mExistingPackages) assertThat(testPackageSetting.usesLibraryFiles).hasSize(1) @@ -250,7 +250,7 @@ class SharedLibrariesImplTest { testPackageSetting.setPkgStateLibraryFiles(listOf()) assertThat(testPackageSetting.usesLibraryFiles).isEmpty() - mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting, + mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg, testPackageSetting, null /* changingLib */, null /* changingLibSetting */, mExistingPackages) assertThat(testPackageSetting.usesLibraryFiles).hasSize(2) @@ -264,7 +264,7 @@ class SharedLibrariesImplTest { testPackageSetting.setPkgStateLibraryFiles(listOf()) assertThat(testPackageSetting.usesLibraryFiles).isEmpty() - mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting, + mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg, testPackageSetting, null /* changingLib */, null /* changingLibSetting */, mExistingPackages) assertThat(testPackageSetting.usesLibraryFiles).hasSize(3) |