summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/AppDataHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java27
-rw-r--r--services/core/java/com/android/server/pm/FileInstallArgs.java268
-rw-r--r--services/core/java/com/android/server/pm/InstallArgs.java40
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java390
-rw-r--r--services/core/java/com/android/server/pm/InstallingSession.java318
-rw-r--r--services/core/java/com/android/server/pm/MoveInstallArgs.java133
-rw-r--r--services/core/java/com/android/server/pm/MultiPackageInstallingSession.java107
-rw-r--r--services/core/java/com/android/server/pm/PackageHandler.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java4
-rw-r--r--services/core/java/com/android/server/pm/ReconciledPackage.java3
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java112
-rw-r--r--services/core/java/com/android/server/pm/SharedLibrariesImpl.java137
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt18
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)