Merge "[pm] refactor InstallArgs"
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
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;
|
||||
}
|
||||
|
||||
/** @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;
|
||||
}
|
||||
|
||||
UserHandle getUser() {
|
||||
return mUser;
|
||||
String getCodePath() {
|
||||
return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -795,127 +785,15 @@ 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1010,11 +888,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");
|
||||
@@ -1039,7 +918,7 @@ final class InstallPackageHelper {
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
}
|
||||
executePostCommitSteps(commitRequest);
|
||||
executePostCommitStepsLIF(commitRequest);
|
||||
} finally {
|
||||
if (success) {
|
||||
for (InstallRequest request : requests) {
|
||||
@@ -1061,7 +940,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()) {
|
||||
@@ -1288,7 +1167,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());
|
||||
}
|
||||
@@ -1541,7 +1420,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");
|
||||
}
|
||||
|
||||
@@ -1805,6 +1684,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
|
||||
@@ -1902,7 +1857,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();
|
||||
@@ -1973,12 +1927,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,
|
||||
@@ -1991,7 +1945,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) {
|
||||
@@ -2261,7 +2215,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
|
||||
@@ -2652,9 +2607,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;
|
||||
@@ -2892,9 +2845,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
|
||||
@@ -3028,7 +2979,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) {
|
||||
@@ -3100,14 +3051,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;
|
||||
}
|
||||
}
|
||||
@@ -3150,7 +3101,7 @@ final class InstallPackageHelper {
|
||||
if (!dstCodePath.exists()) {
|
||||
return null;
|
||||
}
|
||||
new RemovePackageHelper(mPm).removeCodePathLI(dstCodePath);
|
||||
new RemovePackageHelper(mPm).removeCodePath(dstCodePath);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -3236,16 +3187,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);
|
||||
@@ -3348,7 +3299,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());
|
||||
}
|
||||
|
||||
@@ -3358,7 +3309,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
|
||||
@@ -3409,10 +3360,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());
|
||||
@@ -3425,7 +3378,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);
|
||||
}
|
||||
@@ -3586,7 +3539,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3622,11 +3575,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: "
|
||||
@@ -3639,7 +3594,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() + "]");
|
||||
@@ -3654,7 +3609,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);
|
||||
@@ -3688,7 +3643,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,
|
||||
@@ -3770,11 +3725,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,
|
||||
@@ -3856,7 +3813,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,
|
||||
@@ -3893,6 +3850,7 @@ final class InstallPackageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mPm.mInstallLock")
|
||||
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
|
||||
@ParsingPackageUtils.ParseFlags int parseFlags,
|
||||
@PackageManagerService.ScanFlags int scanFlags,
|
||||
@@ -3975,10 +3933,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());
|
||||
}
|
||||
@@ -4060,13 +4018,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
|
||||
@@ -4091,7 +4047,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;
|
||||
}
|
||||
@@ -4398,8 +4353,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 "
|
||||
@@ -4417,8 +4374,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())) {
|
||||
@@ -4430,9 +4389,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 "
|
||||
@@ -4452,13 +4413,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 "
|
||||
|
||||
@@ -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,20 +266,91 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the install reason matches what we know about the package installer (e.g. whether
|
||||
* it is acting on behalf on an enterprise or the user).
|
||||
@@ -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))
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
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;
|
||||
boolean removeSharedLibrary(@NonNull String libName, long version) {
|
||||
synchronized (mPm.mLock) {
|
||||
WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
|
||||
if (versionedLib == null) {
|
||||
return false;
|
||||
}
|
||||
for (VersionedPackage dependentPackage : dependents) {
|
||||
final PackageSetting ps = mPm.mSettings.getPackageLPr(
|
||||
dependentPackage.getPackageName());
|
||||
if (ps != null) {
|
||||
ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
|
||||
final int libIdx = versionedLib.indexOfKey(version);
|
||||
if (libIdx < 0) {
|
||||
return false;
|
||||
}
|
||||
SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user