Consolidate installation logics from params/args classes

Move mLocks/mSettings/mPackages dependencies from InstallParams,
PackageHandler, VerificationParams into InstallPackageHelper.

Also cleaning up InitAndSystemPackageHelper to move some of the
core installation logic into InstallPackageHelper.

Current goal is to have the "core" installation logic in one place.
"core" means code blocks that uses mLock/mSettings/mPackages during
installation.

BYPASS_INCLUSIVE_LANGUAGE_REASON=need to deprecate some old constant
names first

BUG: 198177734
BUG: 201815903
Test: manual
Change-Id: Idb2bf634ce58e968846d6f56c1d501ee8b3aafa3
This commit is contained in:
Songchun Fan
2021-10-25 10:12:27 -07:00
parent 2f96a4f646
commit 788947b76d
11 changed files with 2826 additions and 2848 deletions

View File

@@ -83,19 +83,15 @@ final class DeletePackageHelper {
private final UserManagerInternal mUserManagerInternal;
private final PermissionManagerServiceInternal mPermissionManager;
private final RemovePackageHelper mRemovePackageHelper;
// TODO(b/201815903): remove dependency to InitAndSystemPackageHelper
private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
private final AppDataHelper mAppDataHelper;
// TODO(b/198166813): remove PMS dependency
DeletePackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper,
InitAndSystemPackageHelper initAndSystemPackageHelper,
AppDataHelper appDataHelper) {
mPm = pm;
mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
mRemovePackageHelper = removePackageHelper;
mInitAndSystemPackageHelper = initAndSystemPackageHelper;
mAppDataHelper = appDataHelper;
}
@@ -105,7 +101,6 @@ final class DeletePackageHelper {
mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
mRemovePackageHelper = new RemovePackageHelper(mPm, mAppDataHelper);
mInitAndSystemPackageHelper = mPm.getInitAndSystemPackageHelper();
}
/**
@@ -282,7 +277,7 @@ final class DeletePackageHelper {
Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ stubPkg.getPackageName());
}
mInitAndSystemPackageHelper.enableCompressedPackage(stubPkg, stubPs);
new InstallPackageHelper(mPm).enableCompressedPackage(stubPkg, stubPs);
} else if (DEBUG_COMPRESSION) {
Slog.i(TAG, "System stub disabled for all users, leaving uncompressed "
+ "after removal; pkg: " + stubPkg.getPackageName());
@@ -422,7 +417,7 @@ final class DeletePackageHelper {
// as well and fall back to existing code in system partition
PackageSetting disabledPs = deleteInstalledSystemPackage(action, ps, allUserHandles,
flags, outInfo, writeSettings);
mInitAndSystemPackageHelper.restoreDisabledSystemPackageLIF(
new InstallPackageHelper(mPm).restoreDisabledSystemPackageLIF(
action, ps, allUserHandles, outInfo, writeSettings, disabledPs);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.getPackageName());

View File

@@ -41,14 +41,12 @@ public final class DomainVerificationConnection implements DomainVerificationSer
final PackageManagerService mPm;
final PackageManagerInternal mPmInternal;
final UserManagerInternal mUmInternal;
final VerificationHelper mVerificationHelper;
// TODO(b/198166813): remove PMS dependency
DomainVerificationConnection(PackageManagerService pm) {
mPm = pm;
mPmInternal = mPm.mInjector.getLocalService(PackageManagerInternal.class);
mUmInternal = mPm.mInjector.getLocalService(UserManagerInternal.class);
mVerificationHelper = new VerificationHelper(mPm.mContext);
}
@Override
@@ -79,7 +77,7 @@ public final class DomainVerificationConnection implements DomainVerificationSer
@Override
public long getPowerSaveTempWhitelistAppDuration() {
return mVerificationHelper.getVerificationTimeout();
return VerificationUtils.getVerificationTimeout(mPm.mContext);
}
@Override

View File

@@ -16,22 +16,12 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.TAG;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import android.annotation.NonNull;
import android.os.UserHandle;
import android.util.Slog;
abstract class HandlerParams {
/** User handle for the user requesting the information or installation. */
@@ -40,15 +30,13 @@ abstract class HandlerParams {
int mTraceCookie;
@NonNull
final PackageManagerService mPm;
final VerificationHelper mVerificationHelper;
final BroadcastHelper mBroadcastHelper;
final InstallPackageHelper mInstallPackageHelper;
// TODO(b/198166813): remove PMS dependency
HandlerParams(UserHandle user, PackageManagerService pm) {
mUser = user;
mPm = pm;
mVerificationHelper = new VerificationHelper(mPm.mContext);
mBroadcastHelper = new BroadcastHelper(mPm.mInjector);
mInstallPackageHelper = new InstallPackageHelper(mPm);
}
UserHandle getUser() {
@@ -73,135 +61,4 @@ abstract class HandlerParams {
abstract void handleStartCopy();
abstract void handleReturnCode();
Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
long requiredInstalledVersionCode, int installFlags) {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
return verifyReplacingVersionCodeForApex(
pkgLite, requiredInstalledVersionCode, installFlags);
}
String packageName = pkgLite.packageName;
synchronized (mPm.mLock) {
// Package which currently owns the data that the new package will own if installed.
// If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
// will be null whereas dataOwnerPkg will contain information about the package
// which was uninstalled while keeping its data.
AndroidPackage dataOwnerPkg = mPm.mPackages.get(packageName);
if (dataOwnerPkg == null) {
PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
if (ps != null) {
dataOwnerPkg = ps.getPkg();
}
}
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (dataOwnerPkg == null) {
String errorMsg = "Required installed version code was "
+ requiredInstalledVersionCode
+ " but package is not installed";
Slog.w(TAG, errorMsg);
return Pair.create(
PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
}
if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
String errorMsg = "Required installed version code was "
+ requiredInstalledVersionCode
+ " but actual installed version is "
+ dataOwnerPkg.getLongVersionCode();
Slog.w(TAG, errorMsg);
return Pair.create(
PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
}
}
if (dataOwnerPkg != null) {
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
dataOwnerPkg.isDebuggable())) {
try {
checkDowngrade(dataOwnerPkg, pkgLite);
} catch (PackageManagerException e) {
String errorMsg = "Downgrade detected: " + e.getMessage();
Slog.w(TAG, errorMsg);
return Pair.create(
PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
}
}
}
}
return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
}
private Pair<Integer, String> verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
long requiredInstalledVersionCode, int installFlags) {
String packageName = pkgLite.packageName;
final PackageInfo activePackage = mPm.mApexManager.getPackageInfo(packageName,
ApexManager.MATCH_ACTIVE_PACKAGE);
if (activePackage == null) {
String errorMsg = "Attempting to install new APEX package " + packageName;
Slog.w(TAG, errorMsg);
return Pair.create(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, errorMsg);
}
final long activeVersion = activePackage.getLongVersionCode();
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST
&& activeVersion != requiredInstalledVersionCode) {
String errorMsg = "Installed version of APEX package " + packageName
+ " does not match required. Active version: " + activeVersion
+ " required: " + requiredInstalledVersionCode;
Slog.w(TAG, errorMsg);
return Pair.create(PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
}
final boolean isAppDebuggable = (activePackage.applicationInfo.flags
& ApplicationInfo.FLAG_DEBUGGABLE) != 0;
final long newVersionCode = pkgLite.getLongVersionCode();
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, isAppDebuggable)
&& newVersionCode < activeVersion) {
String errorMsg = "Downgrade of APEX package " + packageName
+ " is not allowed. Active version: " + activeVersion
+ " attempted: " + newVersionCode;
Slog.w(TAG, errorMsg);
return Pair.create(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
}
return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
}
/**
* Check and throw if the given before/after packages would be considered a
* downgrade.
*/
private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
throws PackageManagerException {
if (after.getLongVersionCode() < before.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update version code " + after.versionCode + " is older than current "
+ before.getLongVersionCode());
} else if (after.getLongVersionCode() == before.getLongVersionCode()) {
if (after.baseRevisionCode < before.getBaseRevisionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update base revision code " + after.baseRevisionCode
+ " is older than current " + before.getBaseRevisionCode());
}
if (!ArrayUtils.isEmpty(after.splitNames)) {
for (int i = 0; i < after.splitNames.length; i++) {
final String splitName = after.splitNames[i];
final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
if (j != -1) {
if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update split " + splitName + " revision code "
+ after.splitRevisionCodes[i]
+ " is older than current "
+ before.getSplitRevisionCodes()[j]);
}
}
}
}
}
}
}

View File

@@ -16,22 +16,13 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
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.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
@@ -42,31 +33,21 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Environment;
import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.system.ErrnoException;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.F2fsUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -74,15 +55,10 @@ import com.android.server.EventLogTags;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.utils.WatchedArrayMap;
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.concurrent.ExecutorService;
@@ -270,6 +246,8 @@ final class InitAndSystemPackageHelper {
* If the package is scanned, it's not erased.
*/
final AndroidPackage scannedPkg = mPm.mPackages.get(ps.getPackageName());
final PackageSetting disabledPs =
mPm.mSettings.getDisabledSystemPkgLPr(ps.getPackageName());
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
@@ -278,7 +256,7 @@ final class InitAndSystemPackageHelper {
* scanned package so the previously user-installed
* application can be scanned.
*/
if (mPm.mSettings.isDisabledSystemPackageLPr(ps.getPackageName())) {
if (disabledPs != null) {
logCriticalInfo(Log.WARN,
"Expecting better updated system app for "
+ ps.getPackageName()
@@ -294,7 +272,7 @@ final class InitAndSystemPackageHelper {
continue;
}
if (!mPm.mSettings.isDisabledSystemPackageLPr(ps.getPackageName())) {
if (disabledPs == null) {
logCriticalInfo(Log.WARN, "System package " + ps.getPackageName()
+ " no longer exists; its data will be wiped");
mRemovePackageHelper.removePackageDataLIF(ps, userIds, null, 0, false);
@@ -303,8 +281,6 @@ final class InitAndSystemPackageHelper {
// been removed. check the code path still exists and check there's
// still a package. the latter can happen if an OTA keeps the same
// code path, but, changes the package name.
final PackageSetting disabledPs =
mPm.mSettings.getDisabledSystemPkgLPr(ps.getPackageName());
if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
|| disabledPs.getPkg() == null) {
possiblyDeletedUpdatedSystemApps.add(ps.getPackageName());
@@ -454,7 +430,7 @@ final class InitAndSystemPackageHelper {
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
installSystemStubPackages(stubSystemApps, mScanFlags);
new InstallPackageHelper(mPm).installSystemStubPackages(stubSystemApps, mScanFlags);
final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- cachedSystemApps;
@@ -568,403 +544,11 @@ final class InitAndSystemPackageHelper {
}
}
/**
* Uncompress and install stub applications.
* <p>In order to save space on the system partition, some applications are shipped in a
* compressed form. In addition the compressed bits for the full application, the
* system image contains a tiny stub comprised of only the Android manifest.
* <p>During the first boot, attempt to uncompress and install the full application. If
* the application can't be installed for any reason, disable the stub and prevent
* uncompressing the full application during future boots.
* <p>In order to forcefully attempt an installation of a full application, go to app
* settings and enable the application.
*/
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
@PackageManagerService.ScanFlags int scanFlags) {
for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
final String packageName = systemStubPackageNames.get(i);
// skip if the system package is already disabled
if (mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
systemStubPackageNames.remove(i);
continue;
}
// skip if the package isn't installed (?!); this should never happen
final AndroidPackage pkg = mPm.mPackages.get(packageName);
if (pkg == null) {
systemStubPackageNames.remove(i);
continue;
}
// skip if the package has been disabled by the user
final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
if (ps != null) {
final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
systemStubPackageNames.remove(i);
continue;
}
}
// install the package to replace the stub on /system
try {
installStubPackageLI(pkg, 0, scanFlags);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
UserHandle.USER_SYSTEM, "android");
systemStubPackageNames.remove(i);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
}
// any failed attempt to install the package will be cleaned up later
}
// disable any stub still left; these failed to install the full application
for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
final String pkgName = systemStubPackageNames.get(i);
final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
}
}
/**
* Extract, install and enable a stub package.
* <p>If the compressed file can not be extracted / installed for any reason, the stub
* APK will be installed and the package will be disabled. To recover from this situation,
* the user will need to go into system settings and re-enable the package.
*/
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
public boolean enableCompressedPackage(AndroidPackage stubPkg,
@NonNull PackageSetting stubPkgSetting) {
final int parseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_CHATTY
| ParsingPackageUtils.PARSE_ENFORCE_CODE;
synchronized (mPm.mInstallLock) {
final AndroidPackage pkg;
try (PackageFreezer freezer =
mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
synchronized (mPm.mLock) {
mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
try {
mPm.updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
Collections.unmodifiableMap(mPm.mPackages));
} catch (PackageManagerException e) {
Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
mPm.mPermissionManager.onPackageInstalled(pkg,
Process.INVALID_UID /* previousAppId */,
PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
UserHandle.USER_ALL);
mPm.writeSettingsLPrTEMP();
}
} catch (PackageManagerException e) {
// Whoops! Something went very wrong; roll back to the stub and disable the package
try (PackageFreezer freezer =
mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
synchronized (mPm.mLock) {
// NOTE: Ensure the system package is enabled; even for a compressed stub.
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
}
installPackageFromSystemLIF(stubPkg.getPath(),
mPm.mUserManager.getUserIds() /*allUserHandles*/,
null /*origUserHandles*/,
true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
pme);
} finally {
// Disable the package; the stub by itself is not runnable
synchronized (mPm.mLock) {
final PackageSetting stubPs = mPm.mSettings.getPackageLPr(
stubPkg.getPackageName());
if (stubPs != null) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
}
mPm.writeSettingsLPrTEMP();
}
}
return false;
}
mAppDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(),
pkg.getBaseApkPath(), pkg.getSplitCodePaths());
}
return true;
}
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags)
throws PackageManagerException {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
}
// uncompress the binary to its eventual destination on /data
final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
if (scanFile == null) {
throw new PackageManagerException(
"Unable to decompress stub at " + stubPkg.getPath());
}
synchronized (mPm.mLock) {
mPm.mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
}
mRemovePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
final ScanPackageHelper scanPackageHelper = new ScanPackageHelper(mPm);
try {
return scanPackageHelper.scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
// Remove the failed install
mRemovePackageHelper.removeCodePathLI(scanFile);
throw e;
}
}
/**
* Decompresses the given package on the system image onto
* the /data partition.
* @return The directory the package was decompressed into. Otherwise, {@code null}.
*/
@GuardedBy("mPm.mInstallLock")
private File decompressPackage(String packageName, String codePath) {
final File[] compressedFiles = getCompressedFiles(codePath);
if (compressedFiles == null || compressedFiles.length == 0) {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "No files to decompress: " + codePath);
}
return null;
}
final File dstCodePath =
PackageManagerServiceUtils.getNextCodePath(Environment.getDataAppDirectory(null),
packageName);
int ret = PackageManager.INSTALL_SUCCEEDED;
try {
makeDirRecursive(dstCodePath, 0755);
for (File srcFile : compressedFiles) {
final String srcFileName = srcFile.getName();
final String dstFileName = srcFileName.substring(
0, srcFileName.length() - COMPRESSED_EXTENSION.length());
final File dstFile = new File(dstCodePath, dstFileName);
ret = decompressFile(srcFile, dstFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
+ "; pkg: " + packageName
+ ", file: " + dstFileName);
break;
}
}
} catch (ErrnoException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
+ "; pkg: " + packageName
+ ", err: " + e.errno);
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(dstCodePath);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
null /*abiOverride*/, false /*isIncremental*/);
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
+ "; pkg: " + packageName);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// NOTE: During boot, we have to delay releasing cblocks for no other reason than
// we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}.
// When we no longer need to read that setting, cblock release can occur always
// occur here directly
if (!mPm.isSystemReady()) {
if (mPm.mReleaseOnSystemReady == null) {
mPm.mReleaseOnSystemReady = new ArrayList<>();
}
mPm.mReleaseOnSystemReady.add(dstCodePath);
} else {
final ContentResolver resolver = mPm.mContext.getContentResolver();
F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath);
}
}
if (ret != PackageManager.INSTALL_SUCCEEDED) {
if (!dstCodePath.exists()) {
return null;
}
mRemovePackageHelper.removeCodePathLI(dstCodePath);
return null;
}
return dstCodePath;
}
@GuardedBy("mPm.mLock")
private void enableSystemPackageLPw(AndroidPackage pkg) {
mPm.mSettings.enableSystemPackageLPw(pkg.getPackageName());
}
/**
* Tries to restore the disabled system package after an update has been deleted.
*/
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
public void restoreDisabledSystemPackageLIF(DeletePackageAction action,
PackageSetting deletedPs, @NonNull int[] allUserHandles,
@Nullable PackageRemovedInfo outInfo,
boolean writeSettings,
PackageSetting disabledPs)
throws SystemDeleteException {
// writer
synchronized (mPm.mLock) {
// NOTE: The system package always needs to be enabled; even if it's for
// a compressed stub. If we don't, installing the system package fails
// during scan [scanning checks the disabled packages]. We will reverse
// this later, after we've "installed" the stub.
// Reinstate the old system package
enableSystemPackageLPw(disabledPs.getPkg());
// Remove any native libraries from the upgraded package.
removeNativeBinariesLI(deletedPs);
}
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPs.getPackageName() + ": "
+ e.getMessage());
// TODO(b/194319951): can we avoid this; throw would come from scan...
throw new SystemDeleteException(e);
} finally {
if (disabledPs.getPkg().isStub()) {
// We've re-installed the stub; make sure it's disabled here. If package was
// originally enabled, we'll install the compressed version of the application
// and re-enable it afterward.
final PackageSetting stubPs = mPm.mSettings.getPackageLPr(
deletedPs.getPackageName());
if (stubPs != null) {
int userId = action.mUser == null
? UserHandle.USER_ALL : action.mUser.getIdentifier();
if (userId == UserHandle.USER_ALL) {
for (int aUserId : allUserHandles) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android");
}
} else if (userId >= UserHandle.USER_SYSTEM) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android");
}
}
}
}
}
private void removeNativeBinariesLI(PackageSetting ps) {
if (ps != null) {
NativeLibraryHelper.removeNativeBinariesLI(ps.getLegacyNativeLibraryPath());
}
}
/**
* Installs a package that's already on the system partition.
*/
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private void installPackageFromSystemLIF(@NonNull String codePathString,
@NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
throws PackageManagerException {
final File codePath = new File(codePathString);
@ParsingPackageUtils.ParseFlags int parseFlags =
mPm.getDefParseFlags()
| ParsingPackageUtils.PARSE_MUST_BE_APK
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.containsFile(codePath)) {
scanFlags |= partition.scanFlag;
if (partition.containsPrivApp(codePath)) {
scanFlags |= SCAN_AS_PRIVILEGED;
}
break;
}
}
final ScanPackageHelper scanPackageHelper = new ScanPackageHelper(mPm);
final AndroidPackage pkg =
scanPackageHelper.scanPackageTracedLI(
codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
try {
// update shared libraries for the newly re-installed system package
mPm.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
Collections.unmodifiableMap(mPm.mPackages));
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
// writer
synchronized (mPm.mLock) {
PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
final boolean applyUserRestrictions = origUserHandles != null;
if (applyUserRestrictions) {
boolean installedStateChanged = false;
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across reinstall");
}
for (int userId : allUserHandles) {
final boolean installed = ArrayUtils.contains(origUserHandles, userId);
if (DEBUG_REMOVE) {
Slog.d(TAG, " user " + userId + " => " + installed);
}
if (installed != ps.getInstalled(userId)) {
installedStateChanged = true;
}
ps.setInstalled(installed, userId);
if (installed) {
ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
}
}
// Regardless of writeSettings we need to ensure that this restriction
// state propagation is persisted
mPm.mSettings.writeAllUsersPackageRestrictionsLPr();
if (installedStateChanged) {
mPm.mSettings.writeKernelMappingLPr(ps);
}
}
// The method below will take care of removing obsolete permissions and granting
// install permissions.
mPm.mPermissionManager.onPackageInstalled(pkg,
Process.INVALID_UID /* previousAppId */,
PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
UserHandle.USER_ALL);
for (final int userId : allUserHandles) {
if (applyUserRestrictions) {
mPm.mSettings.writePermissionStateForUserLPr(userId, false);
}
}
// can downgrade to reader here
if (writeSettings) {
mPm.writeSettingsLPrTEMP();
}
}
}
public boolean isExpectingBetter(String packageName) {
return mExpectingBetter.containsKey(packageName);
}
public List<ScanPartition> getDirsToScanAsSystem() {
return mDirsToScanAsSystem;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,20 +16,15 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION;
import static com.android.server.pm.PackageManagerService.DEBUG_BACKUP;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEFAULT_VERIFICATION_RESPONSE;
import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_INSTALL_OBSERVER;
import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_POST_DELETE;
import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_POST_DELETE_DELAY_MS;
import static com.android.server.pm.PackageManagerService.DOMAIN_VERIFICATION;
import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_STATUS;
import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT;
import static com.android.server.pm.PackageManagerService.INIT_COPY;
@@ -46,15 +41,11 @@ import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_RESTRICT
import static com.android.server.pm.PackageManagerService.WRITE_SETTINGS;
import android.content.Intent;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.InstantAppRequest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -62,39 +53,20 @@ import android.os.Process;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.stats.storage.StorageEnums;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import dalvik.system.VMRuntime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
/**
* Part of PackageManagerService that handles events.
*/
public final class PackageHandler extends Handler {
final class PackageHandler extends Handler {
private final PackageManagerService mPm;
private final VerificationHelper mVerificationHelper;
private final BroadcastHelper mBroadcastHelper;
private final InstallPackageHelper mInstallPackageHelper;
PackageHandler(Looper looper, PackageManagerService pm) {
super(looper);
mPm = pm;
mVerificationHelper = new VerificationHelper(mPm.mContext);
mBroadcastHelper = new BroadcastHelper(mPm.mInjector);
mInstallPackageHelper = new InstallPackageHelper(mPm);
}
@Override
@@ -121,46 +93,7 @@ public final class PackageHandler extends Handler {
break;
}
case SEND_PENDING_BROADCAST: {
String[] packages;
ArrayList<String>[] components;
int size = 0;
int[] uids;
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPm.mLock) {
size = mPm.mPendingBroadcasts.size();
if (size <= 0) {
// Nothing to be done. Just return
return;
}
packages = new String[size];
components = new ArrayList[size];
uids = new int[size];
int i = 0; // filling out the above arrays
for (int n = 0; n < mPm.mPendingBroadcasts.userIdCount(); n++) {
final int packageUserId = mPm.mPendingBroadcasts.userIdAt(n);
final ArrayMap<String, ArrayList<String>> componentsToBroadcast =
mPm.mPendingBroadcasts.packagesForUserId(packageUserId);
final int numComponents = componentsToBroadcast.size();
for (int index = 0; i < size && index < numComponents; index++) {
packages[i] = componentsToBroadcast.keyAt(index);
components[i] = componentsToBroadcast.valueAt(index);
final PackageSetting ps = mPm.mSettings.getPackageLPr(packages[i]);
uids[i] = (ps != null)
? UserHandle.getUid(packageUserId, ps.getAppId())
: -1;
i++;
}
}
size = i;
mPm.mPendingBroadcasts.clear();
}
// Send broadcasts
for (int i = 0; i < size; i++) {
mPm.sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
components[i], uids[i], null /* reason */);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mInstallPackageHelper.sendPendingBroadcasts();
break;
}
case POST_INSTALL: {
@@ -177,23 +110,7 @@ public final class PackageHandler extends Handler {
if (data != null && data.mPostInstallRunnable != null) {
data.mPostInstallRunnable.run();
} else if (data != null && data.args != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
final boolean killApp = (args.mInstallFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
final boolean virtualPreload = ((args.mInstallFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
handlePackagePostInstall(parentRes, killApp, virtualPreload,
didRestore, args.mInstallSource.installerPackageName,
args.mObserver, args.mDataLoaderType);
// Log tracing if needed
if (args.mTraceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.mTraceMethod,
args.mTraceCookie);
}
mInstallPackageHelper.handlePackagePostInstall(data.res, data.args, didRestore);
} else if (DEBUG_INSTALL) {
// No post-install when we run restore from installExistingPackageForUser
Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
@@ -217,31 +134,17 @@ public final class PackageHandler extends Handler {
} break;
case WRITE_SETTINGS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPm.mLock) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
mPm.writeSettingsLPrTEMP();
mPm.mDirtyUsers.clear();
}
mPm.writeSettings();
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case WRITE_PACKAGE_RESTRICTIONS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPm.mLock) {
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mPm.mDirtyUsers) {
mPm.mSettings.writePackageRestrictionsLPr(userId);
}
mPm.mDirtyUsers.clear();
}
mPm.writePendingRestrictions();
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case WRITE_PACKAGE_LIST: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPm.mLock) {
removeMessages(WRITE_PACKAGE_LIST);
mPm.mSettings.writePackageListLPr(msg.arg1);
}
mPm.writePackageList(msg.arg1);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case CHECK_PENDING_VERIFICATION: {
@@ -262,13 +165,13 @@ public final class PackageHandler extends Handler {
Slog.i(TAG, "Continuing with installation of " + originUri);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
mVerificationHelper.broadcastPackageVerified(verificationId, originUri,
VerificationUtils.broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType,
user);
user, mPm.mContext);
} else {
mVerificationHelper.broadcastPackageVerified(verificationId, originUri,
VerificationUtils.broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT, null,
params.mDataLoaderType, user);
params.mDataLoaderType, user, mPm.mContext);
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
state.setVerifierResponse(Binder.getCallingUid(),
@@ -343,8 +246,9 @@ public final class PackageHandler extends Handler {
final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
if (state.isInstallAllowed()) {
mVerificationHelper.broadcastPackageVerified(verificationId, originUri,
response.code, null, params.mDataLoaderType, params.getUser());
VerificationUtils.broadcastPackageVerified(verificationId, originUri,
response.code, null, params.mDataLoaderType, params.getUser(),
mPm.mContext);
} else {
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
@@ -475,285 +379,6 @@ public final class PackageHandler extends Handler {
}
}
private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
boolean virtualPreload, boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
final String packageName = res.mName;
final PackageSetting pkgSetting = succeeded ? mPm.getPackageSetting(packageName) : null;
final boolean removedBeforeUpdate = (pkgSetting == null)
|| (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(
res.mPkg.getPath()));
if (succeeded && removedBeforeUpdate) {
Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
+ "could be executed");
res.mReturnCode = INSTALL_FAILED_PACKAGE_CHANGED;
res.mReturnMsg = "Package was removed before install could complete.";
// 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);
}
}
mPm.notifyInstallObserver(res, installObserver);
return;
}
if (succeeded) {
// Clear the uid cache after we installed a new package.
mPm.mPerUidReadTimeoutsCache = null;
// Send the removed broadcasts
if (res.mRemovedInfo != null) {
res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
final String installerPackageName =
res.mInstallerPackageName != null
? res.mInstallerPackageName
: res.mRemovedInfo != null
? res.mRemovedInfo.mInstallerPackageName
: null;
synchronized (mPm.mLock) {
mPm.mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers);
}
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
int[] firstUserIds = EMPTY_INT_ARRAY;
int[] firstInstantUserIds = EMPTY_INT_ARRAY;
int[] updateUserIds = EMPTY_INT_ARRAY;
int[] instantUserIds = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.mOrigUsers == null || res.mOrigUsers.length == 0;
for (int newUser : res.mNewUsers) {
final boolean isInstantApp = pkgSetting.getInstantApp(newUser);
if (allNewUsers) {
if (isInstantApp) {
firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
} else {
firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
}
continue;
}
boolean isNew = true;
for (int origUser : res.mOrigUsers) {
if (origUser == newUser) {
isNew = false;
break;
}
}
if (isNew) {
if (isInstantApp) {
firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
} else {
firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
}
} else {
if (isInstantApp) {
instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
} else {
updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
}
}
}
// Send installed broadcasts if the package is not a static shared lib.
if (res.mPkg.getStaticSharedLibName() == null) {
mPm.mProcessLoggingHandler.invalidateBaseApkHash(res.mPkg.getBaseApkPath());
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.mUid);
boolean isSystem = res.mPkg.isSystem();
mPm.sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
dataLoaderType);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.mUid);
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
// Send to all running apps.
final SparseArray<int[]> newBroadcastAllowList;
synchronized (mPm.mLock) {
newBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
mPm.getPackageSettingInternal(res.mName, Process.SYSTEM_UID),
updateUserIds, mPm.mSettings.getPackagesLocked());
}
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, newBroadcastAllowList, null);
if (installerPackageName != null) {
// Send to the installer, even if it's not running.
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// if the required verifier is defined, but, is not the installer of record
// for the package, it gets notified
final boolean notifyVerifier = mPm.mRequiredVerifierPackage != null
&& !mPm.mRequiredVerifierPackage.equals(installerPackageName);
if (notifyVerifier) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// If package installer is defined, notify package installer about new
// app installed
if (mPm.mRequiredInstallerPackage != null) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
mPm.mRequiredInstallerPackage, null /*finishedReceiver*/,
firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// Send replaced for users that don't see the package for the first time
if (update) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
null);
if (installerPackageName != null) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
}
if (notifyVerifier) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
}
mPm.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUserIds, instantUserIds,
null /*broadcastAllowList*/,
mBroadcastHelper.getTemporaryAppAllowlistBroadcastOptions(
REASON_PACKAGE_REPLACED).toBundle());
} else if (launchedForRestore && !res.mPkg.isSystem()) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
if (DEBUG_BACKUP) {
Slog.i(TAG, "Post-restore of " + packageName
+ " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
}
mBroadcastHelper.sendFirstLaunchBroadcast(packageName, installerPackage,
firstUserIds, firstInstantUserIds);
}
// Send broadcast package appeared if external for all users
if (res.mPkg.isExternalStorage()) {
if (!update) {
final StorageManager storage = mPm.mInjector.getSystemService(
StorageManager.class);
VolumeInfo volume =
storage.findVolumeByUuid(
StorageManager.convert(
res.mPkg.getVolumeUuid()).toString());
int packageExternalStorageType =
PackageManagerServiceUtils.getPackageExternalStorageType(volume,
res.mPkg.isExternalStorage());
// If the package was installed externally, log it.
if (packageExternalStorageType != StorageEnums.UNKNOWN) {
FrameworkStatsLog.write(
FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
packageExternalStorageType, packageName);
}
}
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
}
final int[] uidArray = new int[]{res.mPkg.getUid()};
ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(packageName);
mBroadcastHelper.sendResourcesChangedBroadcast(
true, true, pkgList, uidArray, null);
}
} else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
AndroidPackage pkg = res.mLibraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
mPm.sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
pkg.getUid(), null);
}
}
// Work that needs to happen on first install within each user
if (firstUserIds != null && firstUserIds.length > 0) {
for (int userId : firstUserIds) {
mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
userId);
}
}
if (allNewUsers && !update) {
mPm.notifyPackageAdded(packageName, res.mUid);
} else {
mPm.notifyPackageChanged(packageName, res.mUid);
}
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
// Remove the replaced package's older resources safely now
InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
if (args != null) {
if (!killApp) {
// If we didn't kill the app, defer the deletion of code/resource files, since
// they may still be in use by the running application. This mitigates problems
// in cases where resources or code is loaded by a new Activity before
// ApplicationInfo changes have propagated to all application threads.
scheduleDeferredNoKillPostDelete(args);
} else {
synchronized (mPm.mInstallLock) {
args.doPostDeleteLI(true);
}
}
} else {
// Force a gc to clear up things. Ask for a background one, it's fine to go on
// and not block here.
VMRuntime.getRuntime().requestConcurrentGC();
}
// Notify DexManager that the package was installed for new users.
// The updated users should already be indexed and the package code paths
// should not change.
// Don't notify the manager for ephemeral apps as they are not expected to
// survive long enough to benefit of background optimizations.
for (int userId : firstUserIds) {
PackageInfo info = mPm.getPackageInfo(packageName, /*flags*/ 0, userId);
// There's a race currently where some install events may interleave with an
// uninstall. This can lead to package info being null (b/36642664).
if (info != null) {
mPm.getDexManager().notifyPackageInstalled(info, userId);
}
}
}
final boolean deferInstallObserver = succeeded && update && !killApp;
if (deferInstallObserver) {
mPm.scheduleDeferredNoKillInstallObserver(res, installObserver);
} else {
mPm.notifyInstallObserver(res, installObserver);
}
}
/**
* Get the default verification agent response code.
*
@@ -777,20 +402,4 @@ public final class PackageHandler extends Handler {
// an easy way to get around the integrity check.
return PackageManager.VERIFICATION_REJECT;
}
/**
* Get the "allow unknown sources" setting.
*
* @return the current "allow unknown sources" setting
*/
private int getUnknownSourcesSettings() {
return android.provider.Settings.Secure.getIntForUser(mPm.mContext.getContentResolver(),
android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
-1, UserHandle.USER_SYSTEM);
}
private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
Message message = obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
}
}

View File

@@ -1250,6 +1250,11 @@ public class PackageManagerService extends IPackageManager.Stub
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
}
void scheduleDeferredNoKillPostDelete(InstallArgs args) {
Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
}
@Override
public void requestChecksums(@NonNull String packageName, boolean includeSplits,
@Checksum.TypeMask int optional,
@@ -1380,6 +1385,38 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
private void writePendingRestrictionsLocked() {
if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mDirtyUsers) {
mSettings.writePackageRestrictionsLPr(userId);
}
mDirtyUsers.clear();
}
}
void writePendingRestrictions() {
synchronized (mLock) {
writePendingRestrictionsLocked();
}
}
void writeSettings() {
synchronized (mLock) {
mHandler.removeMessages(WRITE_SETTINGS);
mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
writeSettingsLPrTEMP();
mDirtyUsers.clear();
}
}
void writePackageList(int userId) {
synchronized (mLock) {
mHandler.removeMessages(WRITE_PACKAGE_LIST);
mSettings.writePackageListLPr(userId);
}
}
public static PackageManagerService main(Context context, Installer installer,
@NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
boolean onlyCore) {
@@ -1772,7 +1809,7 @@ public class PackageManagerService extends IPackageManager.Stub
mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mInitAndSystemPackageHelper, mAppDataHelper);
mAppDataHelper);
mPreferredActivityHelper = new PreferredActivityHelper(this);
mResolveIntentHelper = new ResolveIntentHelper(this, mPreferredActivityHelper);
mDexOptHelper = new DexOptHelper(this);
@@ -5059,13 +5096,7 @@ public class PackageManagerService extends IPackageManager.Stub
mPackageUsage.writeNow(mSettings.getPackagesLocked());
// This is the last chance to write out pending restriction settings
if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mDirtyUsers) {
mSettings.writePackageRestrictionsLPr(userId);
}
mDirtyUsers.clear();
}
writePendingRestrictionsLocked();
}
}
@@ -7808,7 +7839,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
if (!mInitAndSystemPackageHelper.enableCompressedPackage(deletedPkg, pkgSetting)) {
if (!new InstallPackageHelper(this).enableCompressedPackage(deletedPkg,
pkgSetting)) {
Slog.w(TAG, "Failed setApplicationEnabledSetting: failed to enable "
+ "commpressed package " + setting.getPackageName());
updateAllowed[i] = false;
@@ -11083,11 +11115,24 @@ public class PackageManagerService extends IPackageManager.Stub
return mIsPreNMR1Upgrade;
}
InitAndSystemPackageHelper getInitAndSystemPackageHelper() {
return mInitAndSystemPackageHelper;
}
boolean isOverlayMutable(String packageName) {
return mOverlayConfig.isMutable(packageName);
}
@ScanFlags int getSystemPackageScanFlags(File codePath) {
List<ScanPartition> dirsToScanAsSystem =
mInitAndSystemPackageHelper.getDirsToScanAsSystem();
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = dirsToScanAsSystem.get(i);
if (partition.containsFile(codePath)) {
scanFlags |= partition.scanFlag;
if (partition.containsPrivApp(codePath)) {
scanFlags |= SCAN_AS_PRIVILEGED;
}
break;
}
}
return scanFlags;
}
}

View File

@@ -643,6 +643,35 @@ public class PackageManagerServiceUtils {
return compatMatch;
}
/**
* Decompress files stored in codePath to dstCodePath for a certain package.
*/
public static int decompressFiles(String codePath, File dstCodePath, String packageName) {
final File[] compressedFiles = getCompressedFiles(codePath);
int ret = PackageManager.INSTALL_SUCCEEDED;
try {
makeDirRecursive(dstCodePath, 0755);
for (File srcFile : compressedFiles) {
final String srcFileName = srcFile.getName();
final String dstFileName = srcFileName.substring(
0, srcFileName.length() - COMPRESSED_EXTENSION.length());
final File dstFile = new File(dstCodePath, dstFileName);
ret = decompressFile(srcFile, dstFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
+ "; pkg: " + packageName
+ ", file: " + dstFileName);
break;
}
}
} catch (ErrnoException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
+ "; pkg: " + packageName
+ ", err: " + e.errno);
}
return ret;
}
public static int decompressFile(File srcFile, File dstFile) throws ErrnoException {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "Decompress file"

View File

@@ -51,7 +51,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.VerifierInfo;
import android.content.pm.parsing.PackageLite;
@@ -62,7 +61,6 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.ArraySet;
@@ -70,13 +68,9 @@ import android.util.Pair;
import android.util.Slog;
import com.android.server.DeviceIdleInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.File;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -90,10 +84,6 @@ final class VerificationParams extends HandlerParams {
* milliseconds.
*/
private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
/**
* Whether verification is enabled by default.
*/
private static final boolean DEFAULT_VERIFY_ENABLE = true;
/**
* Timeout duration in milliseconds for enabling package rollback. If we fail to enable
* rollback within that period, the install will proceed without rollback enabled.
@@ -166,7 +156,7 @@ final class VerificationParams extends HandlerParams {
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
Pair<Integer, String> ret = verifyReplacingVersionCode(
Pair<Integer, String> ret = mInstallPackageHelper.verifyReplacingVersionCode(
pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
setReturnCode(ret.first, ret.second);
if (mRet != INSTALL_SUCCEEDED) {
@@ -186,7 +176,7 @@ final class VerificationParams extends HandlerParams {
}
}
void sendApkVerificationRequest(PackageInfoLite pkgLite) {
private void sendApkVerificationRequest(PackageInfoLite pkgLite) {
final int verificationId = mPm.mPendingVerificationToken++;
PackageVerificationState verificationState =
@@ -332,7 +322,7 @@ final class VerificationParams extends HandlerParams {
/**
* Send a request to verifier(s) to verify the package if necessary.
*/
void sendPackageVerificationRequest(
private void sendPackageVerificationRequest(
int verificationId,
PackageInfoLite pkgLite,
PackageVerificationState verificationState) {
@@ -354,7 +344,7 @@ final class VerificationParams extends HandlerParams {
verificationState.setRequiredVerifierUid(requiredUid);
final int installerUid =
mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid;
final boolean isVerificationEnabled = isVerificationEnabled(
final boolean isVerificationEnabled = mInstallPackageHelper.isVerificationEnabled(
pkgLite, verifierUser.getIdentifier(), mInstallFlags, installerUid);
final boolean isV4Signed =
(mSigningDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4);
@@ -404,7 +394,7 @@ final class VerificationParams extends HandlerParams {
DeviceIdleInternal idleController =
mPm.mInjector.getLocalService(DeviceIdleInternal.class);
final long idleDuration = mVerificationHelper.getVerificationTimeout();
final long idleDuration = VerificationUtils.getVerificationTimeout(mPm.mContext);
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setTemporaryAppAllowlist(idleDuration,
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
@@ -461,7 +451,7 @@ final class VerificationParams extends HandlerParams {
.obtainMessage(CHECK_PENDING_VERIFICATION);
msg.arg1 = verificationId;
mPm.mHandler.sendMessageDelayed(msg,
mVerificationHelper.getVerificationTimeout());
VerificationUtils.getVerificationTimeout(mPm.mContext));
}
}, null, 0, null, null);
@@ -498,7 +488,7 @@ final class VerificationParams extends HandlerParams {
continue;
}
final int verifierUid = getUidForVerifier(verifierInfo);
final int verifierUid = mInstallPackageHelper.getUidForVerifier(verifierInfo);
if (verifierUid == -1) {
continue;
}
@@ -514,44 +504,6 @@ final class VerificationParams extends HandlerParams {
return sufficientVerifiers;
}
private int getUidForVerifier(VerifierInfo verifierInfo) {
synchronized (mPm.mLock) {
final AndroidPackage pkg = mPm.mPackages.get(verifierInfo.packageName);
if (pkg == null) {
return -1;
} else if (pkg.getSigningDetails().getSignatures().length != 1) {
Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ " has more than one signature; ignoring");
return -1;
}
/*
* If the public key of the package's signature does not match
* our expected public key, then this is a different package and
* we should skip.
*/
final byte[] expectedPublicKey;
try {
final Signature verifierSig = pkg.getSigningDetails().getSignatures()[0];
final PublicKey publicKey = verifierSig.getPublicKey();
expectedPublicKey = publicKey.getEncoded();
} catch (CertificateException e) {
return -1;
}
final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ " does not have the expected public key; ignoring");
return -1;
}
return pkg.getUid();
}
}
private static ComponentName matchComponentForVerifier(String packageName,
List<ResolveInfo> receivers) {
ActivityInfo targetReceiver = null;
@@ -576,56 +528,6 @@ final class VerificationParams extends HandlerParams {
return new ComponentName(targetReceiver.packageName, targetReceiver.name);
}
/**
* Check whether or not package verification has been enabled.
*
* @return true if verification should be performed
*/
private boolean isVerificationEnabled(
PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) {
if (!DEFAULT_VERIFY_ENABLE) {
return false;
}
// Check if installing from ADB
if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
if (mPm.isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
return true;
}
// Check if the developer wants to skip verification for ADB installs
if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
synchronized (mPm.mLock) {
if (mPm.mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
// Always verify fresh install
return true;
}
}
// Only skip when apk is debuggable
return !pkgInfoLite.debuggable;
}
return Settings.Global.getInt(mPm.mContext.getContentResolver(),
Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
}
// only when not installed from ADB, skip verification for instant apps when
// the installer and verifier are the same.
if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
if (mPm.mInstantAppInstallerActivity != null
&& mPm.mInstantAppInstallerActivity.packageName.equals(
mPm.mRequiredVerifierPackage)) {
try {
mPm.mInjector.getSystemService(AppOpsManager.class)
.checkPackage(installerUid, mPm.mRequiredVerifierPackage);
if (DEBUG_VERIFY) {
Slog.i(TAG, "disable verification for instant app");
}
return false;
} catch (SecurityException ignore) { }
}
}
return true;
}
void populateInstallerExtras(Intent intent) {
intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
mInstallSource.initiatingPackageName);

View File

@@ -27,36 +27,30 @@ import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
public final class VerificationHelper {
final class VerificationUtils {
/**
* The default maximum time to wait for the verification agent to return in
* milliseconds.
*/
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
Context mContext;
public VerificationHelper(Context context) {
mContext = context;
}
/**
* Get the verification agent timeout. Used for both the APK verifier and the
* intent filter verifier.
*
* @return verification timeout in milliseconds
*/
public long getVerificationTimeout() {
long timeout = Settings.Global.getLong(mContext.getContentResolver(),
public static long getVerificationTimeout(Context context) {
long timeout = Settings.Global.getLong(context.getContentResolver(),
Settings.Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT);
// The setting can be used to increase the timeout but not decrease it, since that is
// equivalent to disabling the verifier.
return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
}
public void broadcastPackageVerified(int verificationId, Uri packageUri,
public static void broadcastPackageVerified(int verificationId, Uri packageUri,
int verificationCode, @Nullable String rootHashString, int dataLoaderType,
UserHandle user) {
UserHandle user, Context context) {
final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -67,7 +61,7 @@ public final class VerificationHelper {
}
intent.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
mContext.sendBroadcastAsUser(intent, user,
context.sendBroadcastAsUser(intent, user,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
}
}