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:
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user