Merge "Merge "AbsoluteVolume change custom call to official API" am: d51c3f3a2c am: 29da6bb3e4 am: 548b9eaf35 am: 229680564c am: af22a31d61"
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index 850cf1b..9696d3d 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -242,7 +242,8 @@
// #performDexOptUpgrade. When we do that we should have a
// more granular check here and only update the existing
// profiles.
- if (mPm.mIsUpgrade || mPm.mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
+ if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()
+ || (userId != UserHandle.USER_SYSTEM)) {
mArtManagerService.prepareAppProfiles(pkg, userId,
/* updateReferenceProfileContent= */ false);
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 44e8e66..af9c401 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -251,13 +251,15 @@
resetStatesForNewDexOptRunLocked(Thread.currentThread());
}
PackageManagerService pm = mInjector.getPackageManagerService();
+ DexOptHelper dexOptHelper = new DexOptHelper(pm);
ArraySet<String> packagesToOptimize;
if (packageNames == null) {
- packagesToOptimize = pm.getOptimizablePackages();
+ packagesToOptimize = dexOptHelper.getOptimizablePackages();
} else {
packagesToOptimize = new ArraySet<>(packageNames);
}
- return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
+ return runIdleOptimization(pm, dexOptHelper, packagesToOptimize,
+ /* isPostBootUpdate= */ false);
} finally {
Binder.restoreCallingIdentity(identity);
markDexOptCompleted();
@@ -318,7 +320,8 @@
return false;
}
- ArraySet<String> pkgs = pm.getOptimizablePackages();
+ DexOptHelper dexOptHelper = new DexOptHelper(pm);
+ ArraySet<String> pkgs = dexOptHelper.getOptimizablePackages();
if (pkgs.isEmpty()) {
Slog.i(TAG, "No packages to optimize");
markPostBootUpdateCompleted(params);
@@ -344,7 +347,7 @@
tr.traceBegin("jobExecution");
boolean completed = false;
try {
- completed = runIdleOptimization(pm, pkgs,
+ completed = runIdleOptimization(pm, dexOptHelper, pkgs,
params.getJobId() == JOB_POST_BOOT_UPDATE);
} finally { // Those cleanup should be done always.
tr.traceEnd();
@@ -457,7 +460,8 @@
@GuardedBy("mLock")
private void controlDexOptBlockingLocked(boolean block) {
- mInjector.getPackageManagerService().controlDexOptBlocking(block);
+ PackageManagerService pm = mInjector.getPackageManagerService();
+ new DexOptHelper(pm).controlDexOptBlocking(block);
}
private void scheduleAJob(int jobId) {
@@ -507,10 +511,11 @@
}
/** Returns true if completed */
- private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
- boolean isPostBootUpdate) {
+ private boolean runIdleOptimization(PackageManagerService pm, DexOptHelper dexOptHelper,
+ ArraySet<String> pkgs, boolean isPostBootUpdate) {
long lowStorageThreshold = getLowStorageThreshold();
- int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate);
+ int status = idleOptimizePackages(pm, dexOptHelper, pkgs, lowStorageThreshold,
+ isPostBootUpdate);
logStatus(status);
synchronized (mLock) {
mLastExecutionStatus = status;
@@ -557,8 +562,8 @@
}
@Status
- private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
- long lowStorageThreshold, boolean isPostBootUpdate) {
+ private int idleOptimizePackages(PackageManagerService pm, DexOptHelper dexOptHelper,
+ ArraySet<String> pkgs, long lowStorageThreshold, boolean isPostBootUpdate) {
ArraySet<String> updatedPackages = new ArraySet<>();
ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
@@ -595,7 +600,7 @@
// Should be aborted by the scheduler.
return abortCode;
}
- @DexOptResult int downgradeResult = downgradePackage(pm, pkg,
+ @DexOptResult int downgradeResult = downgradePackage(pm, dexOptHelper, pkg,
/* isForPrimaryDex= */ true, isPostBootUpdate);
if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
@@ -606,7 +611,7 @@
return status;
}
if (supportSecondaryDex) {
- downgradeResult = downgradePackage(pm, pkg,
+ downgradeResult = downgradePackage(pm, dexOptHelper, pkg,
/* isForPrimaryDex= */false, isPostBootUpdate);
status = convertPackageDexOptimizerStatusToInternal(downgradeResult);
if (status != STATUS_OK) {
@@ -620,8 +625,9 @@
}
}
- @Status int primaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
- /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
+ @Status int primaryResult = optimizePackages(dexOptHelper, pkgs,
+ lowStorageThreshold, /*isForPrimaryDex=*/ true, updatedPackages,
+ isPostBootUpdate);
if (primaryResult != STATUS_OK) {
return primaryResult;
}
@@ -630,9 +636,9 @@
return STATUS_OK;
}
- @Status int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
- /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
- isPostBootUpdate);
+ @Status int secondaryResult = optimizePackages(dexOptHelper, pkgs,
+ lowStorageThreshold, /*isForPrimaryDex*/ false,
+ updatedPackagesDueToSecondaryDex, isPostBootUpdate);
return secondaryResult;
} finally {
// Always let the pinner service know about changes.
@@ -645,9 +651,9 @@
}
@Status
- private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
- long lowStorageThreshold, boolean isForPrimaryDex, ArraySet<String> updatedPackages,
- boolean isPostBootUpdate) {
+ private int optimizePackages(DexOptHelper dexOptHelper,
+ ArraySet<String> pkgs, long lowStorageThreshold, boolean isForPrimaryDex,
+ ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
for (String pkg : pkgs) {
int abortCode = abortIdleOptimizations(lowStorageThreshold);
if (abortCode != STATUS_OK) {
@@ -655,7 +661,8 @@
return abortCode;
}
- @DexOptResult int result = optimizePackage(pm, pkg, isForPrimaryDex, isPostBootUpdate);
+ @DexOptResult int result = optimizePackage(dexOptHelper, pkg, isForPrimaryDex,
+ isPostBootUpdate);
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
} else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
@@ -674,7 +681,7 @@
* @return PackageDexOptimizer.DEX_*
*/
@DexOptResult
- private int downgradePackage(PackageManagerService pm, String pkg,
+ private int downgradePackage(PackageManagerService pm, DexOptHelper dexOptHelper, String pkg,
boolean isForPrimaryDex, boolean isPostBootUpdate) {
if (DEBUG) {
Slog.d(TAG, "Downgrading " + pkg);
@@ -697,10 +704,10 @@
// remove their compiler artifacts from dalvik cache.
pm.deleteOatArtifactsOfPackage(pkg);
} else {
- result = performDexOptPrimary(pm, pkg, reason, dexoptFlags);
+ result = performDexOptPrimary(dexOptHelper, pkg, reason, dexoptFlags);
}
} else {
- result = performDexOptSecondary(pm, pkg, reason, dexoptFlags);
+ result = performDexOptSecondary(dexOptHelper, pkg, reason, dexoptFlags);
}
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -726,14 +733,14 @@
*
* Optimize package if needed. Note that there can be no race between
* concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
- * @param pm An instance of PackageManagerService
+ * @param dexOptHelper An instance of DexOptHelper
* @param pkg The package to be downgraded.
* @param isForPrimaryDex Apps can have several dex file, primary and secondary.
* @param isPostBootUpdate is post boot update or not.
* @return PackageDexOptimizer#DEX_OPT_*
*/
@DexOptResult
- private int optimizePackage(PackageManagerService pm, String pkg,
+ private int optimizePackage(DexOptHelper dexOptHelper, String pkg,
boolean isForPrimaryDex, boolean isPostBootUpdate) {
int reason = isPostBootUpdate ? PackageManagerService.REASON_POST_BOOT
: PackageManagerService.REASON_BACKGROUND_DEXOPT;
@@ -746,26 +753,27 @@
// System server share the same code path as primary dex files.
// PackageManagerService will select the right optimization path for it.
if (isForPrimaryDex || PLATFORM_PACKAGE_NAME.equals(pkg)) {
- return performDexOptPrimary(pm, pkg, reason, dexoptFlags);
+ return performDexOptPrimary(dexOptHelper, pkg, reason, dexoptFlags);
} else {
- return performDexOptSecondary(pm, pkg, reason, dexoptFlags);
+ return performDexOptSecondary(dexOptHelper, pkg, reason, dexoptFlags);
}
}
@DexOptResult
- private int performDexOptPrimary(PackageManagerService pm, String pkg, int reason,
+ private int performDexOptPrimary(DexOptHelper dexOptHelper, String pkg, int reason,
int dexoptFlags) {
return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ true,
- () -> pm.performDexOptWithStatus(new DexoptOptions(pkg, reason, dexoptFlags)));
+ () -> dexOptHelper.performDexOptWithStatus(
+ new DexoptOptions(pkg, reason, dexoptFlags)));
}
@DexOptResult
- private int performDexOptSecondary(PackageManagerService pm, String pkg, int reason,
+ private int performDexOptSecondary(DexOptHelper dexOptHelper, String pkg, int reason,
int dexoptFlags) {
DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason,
dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX);
return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ false,
- () -> pm.performDexOpt(dexoptOptions)
+ () -> dexOptHelper.performDexOpt(dexoptOptions)
? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED
);
}
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index f63cc4e..b83f987 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -61,7 +61,7 @@
return mService.mInstantAppInstallerActivity;
}
protected ApplicationInfo androidApplication() {
- return mService.mAndroidApplication;
+ return mService.getCoreAndroidApplication();
}
public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 40668d7..0feb9c5 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -83,6 +83,7 @@
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;
@@ -104,8 +105,7 @@
mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
mRemovePackageHelper = new RemovePackageHelper(mPm, mAppDataHelper);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(mPm, mRemovePackageHelper,
- mAppDataHelper);
+ mInitAndSystemPackageHelper = mPm.getInitAndSystemPackageHelper();
}
/**
@@ -282,8 +282,7 @@
Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ stubPkg.getPackageName());
}
- mInitAndSystemPackageHelper.enableCompressedPackage(stubPkg, stubPs,
- mPm.mDefParseFlags, mPm.getDirsToScanAsSystem());
+ mInitAndSystemPackageHelper.enableCompressedPackage(stubPkg, stubPs);
} else if (DEBUG_COMPRESSION) {
Slog.i(TAG, "System stub disabled for all users, leaving uncompressed "
+ "after removal; pkg: " + stubPkg.getPackageName());
@@ -424,8 +423,7 @@
PackageSetting disabledPs = deleteInstalledSystemPackage(action, ps, allUserHandles,
flags, outInfo, writeSettings);
mInitAndSystemPackageHelper.restoreDisabledSystemPackageLIF(
- action, ps, allUserHandles, outInfo, writeSettings, mPm.mDefParseFlags,
- mPm.getDirsToScanAsSystem(), disabledPs);
+ action, ps, allUserHandles, outInfo, writeSettings, disabledPs);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.getPackageName());
deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
new file mode 100644
index 0000000..9390284
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.PackageManagerService.REASON_BOOT_AFTER_OTA;
+import static com.android.server.pm.PackageManagerService.REASON_CMDLINE;
+import static com.android.server.pm.PackageManagerService.REASON_FIRST_BOOT;
+import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.REMOVE_IF_NULL_PKG;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.dex.ArtManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.server.apphibernation.AppHibernationManagerInternal;
+import com.android.server.apphibernation.AppHibernationService;
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DexoptOptions;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+final class DexOptHelper {
+ private static final long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000;
+
+ private final PackageManagerService mPm;
+
+ public boolean isDexOptDialogShown() {
+ return mDexOptDialogShown;
+ }
+
+ @GuardedBy("mPm.mLock")
+ private boolean mDexOptDialogShown;
+
+ DexOptHelper(PackageManagerService pm) {
+ mPm = pm;
+ }
+
+ /*
+ * Return the prebuilt profile path given a package base code path.
+ */
+ private static String getPrebuildProfilePath(AndroidPackage pkg) {
+ return pkg.getBaseApkPath() + ".prof";
+ }
+
+ /**
+ * Performs dexopt on the set of packages in {@code packages} and returns an int array
+ * containing statistics about the invocation. The array consists of three elements,
+ * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped}
+ * and {@code numberOfPackagesFailed}.
+ */
+ public int[] performDexOptUpgrade(List<AndroidPackage> pkgs, boolean showDialog,
+ final int compilationReason, boolean bootComplete) {
+
+ int numberOfPackagesVisited = 0;
+ int numberOfPackagesOptimized = 0;
+ int numberOfPackagesSkipped = 0;
+ int numberOfPackagesFailed = 0;
+ final int numberOfPackagesToDexopt = pkgs.size();
+
+ for (AndroidPackage pkg : pkgs) {
+ numberOfPackagesVisited++;
+
+ boolean useProfileForDexopt = false;
+
+ if ((mPm.isFirstBoot() || mPm.isDeviceUpgrading()) && pkg.isSystem()) {
+ // Copy over initial preopt profiles since we won't get any JIT samples for methods
+ // that are already compiled.
+ File profileFile = new File(getPrebuildProfilePath(pkg));
+ // Copy profile if it exists.
+ if (profileFile.exists()) {
+ try {
+ // We could also do this lazily before calling dexopt in
+ // PackageDexOptimizer to prevent this happening on first boot. The issue
+ // is that we don't have a good way to say "do this only once".
+ if (!mPm.mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
+ pkg.getUid(), pkg.getPackageName(),
+ ArtManager.getProfileName(null))) {
+ Log.e(TAG, "Installer failed to copy system profile!");
+ } else {
+ // Disabled as this causes speed-profile compilation during first boot
+ // even if things are already compiled.
+ // useProfileForDexopt = true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ",
+ e);
+ }
+ } else {
+ PackageSetting disabledPs = mPm.mSettings.getDisabledSystemPkgLPr(
+ pkg.getPackageName());
+ // Handle compressed APKs in this path. Only do this for stubs with profiles to
+ // minimize the number off apps being speed-profile compiled during first boot.
+ // The other paths will not change the filter.
+ if (disabledPs != null && disabledPs.getPkg().isStub()) {
+ // The package is the stub one, remove the stub suffix to get the normal
+ // package and APK names.
+ String systemProfilePath = getPrebuildProfilePath(disabledPs.getPkg())
+ .replace(STUB_SUFFIX, "");
+ profileFile = new File(systemProfilePath);
+ // If we have a profile for a compressed APK, copy it to the reference
+ // location.
+ // Note that copying the profile here will cause it to override the
+ // reference profile every OTA even though the existing reference profile
+ // may have more data. We can't copy during decompression since the
+ // directories are not set up at that point.
+ if (profileFile.exists()) {
+ try {
+ // We could also do this lazily before calling dexopt in
+ // PackageDexOptimizer to prevent this happening on first boot. The
+ // issue is that we don't have a good way to say "do this only
+ // once".
+ if (!mPm.mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
+ pkg.getUid(), pkg.getPackageName(),
+ ArtManager.getProfileName(null))) {
+ Log.e(TAG, "Failed to copy system profile for stub package!");
+ } else {
+ useProfileForDexopt = true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to copy profile "
+ + profileFile.getAbsolutePath() + " ", e);
+ }
+ }
+ }
+ }
+ }
+
+ if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName());
+ }
+ numberOfPackagesSkipped++;
+ continue;
+ }
+
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of "
+ + numberOfPackagesToDexopt + ": " + pkg.getPackageName());
+ }
+
+ if (showDialog) {
+ try {
+ ActivityManager.getService().showBootMessage(
+ mPm.mContext.getResources().getString(R.string.android_upgrading_apk,
+ numberOfPackagesVisited, numberOfPackagesToDexopt), true);
+ } catch (RemoteException e) {
+ }
+ synchronized (mPm.mLock) {
+ mDexOptDialogShown = true;
+ }
+ }
+
+ int pkgCompilationReason = compilationReason;
+ if (useProfileForDexopt) {
+ // Use background dexopt mode to try and use the profile. Note that this does not
+ // guarantee usage of the profile.
+ pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
+ }
+
+ if (SystemProperties.getBoolean(mPm.PRECOMPILE_LAYOUTS, false)) {
+ mPm.mArtManagerService.compileLayouts(pkg);
+ }
+
+ // checkProfiles is false to avoid merging profiles during boot which
+ // might interfere with background compilation (b/28612421).
+ // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
+ // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
+ // trade-off worth doing to save boot time work.
+ int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
+ if (compilationReason == REASON_FIRST_BOOT) {
+ // TODO: This doesn't cover the upgrade case, we should check for this too.
+ dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
+ }
+ int primaryDexOptStatus = performDexOptTraced(new DexoptOptions(
+ pkg.getPackageName(),
+ pkgCompilationReason,
+ dexoptFlags));
+
+ switch (primaryDexOptStatus) {
+ case PackageDexOptimizer.DEX_OPT_PERFORMED:
+ numberOfPackagesOptimized++;
+ break;
+ case PackageDexOptimizer.DEX_OPT_SKIPPED:
+ numberOfPackagesSkipped++;
+ break;
+ case PackageDexOptimizer.DEX_OPT_CANCELLED:
+ // ignore this case
+ break;
+ case PackageDexOptimizer.DEX_OPT_FAILED:
+ numberOfPackagesFailed++;
+ break;
+ default:
+ Log.e(TAG, "Unexpected dexopt return code " + primaryDexOptStatus);
+ break;
+ }
+ }
+
+ return new int[]{numberOfPackagesOptimized, numberOfPackagesSkipped,
+ numberOfPackagesFailed};
+ }
+
+ public void performPackageDexOptUpgradeIfNeeded() {
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system can request package update");
+
+ // We need to re-extract after an OTA.
+ boolean causeUpgrade = mPm.isDeviceUpgrading();
+
+ // First boot or factory reset.
+ // Note: we also handle devices that are upgrading to N right now as if it is their
+ // first boot, as they do not have profile data.
+ boolean causeFirstBoot = mPm.isFirstBoot() || mPm.isPreNUpgrade();
+
+ if (!causeUpgrade && !causeFirstBoot) {
+ return;
+ }
+
+ List<PackageSetting> pkgSettings;
+ synchronized (mPm.mLock) {
+ pkgSettings = getPackagesForDexopt(mPm.mSettings.getPackagesLocked().values(), mPm);
+ }
+
+ List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
+ for (int index = 0; index < pkgSettings.size(); index++) {
+ pkgs.add(pkgSettings.get(index).getPkg());
+ }
+
+ final long startTime = System.nanoTime();
+ final int[] stats = performDexOptUpgrade(pkgs, mPm.isPreNUpgrade() /* showDialog */,
+ causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT_AFTER_OTA,
+ false /* bootComplete */);
+
+ final int elapsedTimeSeconds =
+ (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
+
+ MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_dexopted", stats[0]);
+ MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_skipped", stats[1]);
+ MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_failed", stats[2]);
+ MetricsLogger.histogram(
+ mPm.mContext, "opt_dialog_num_total", getOptimizablePackages().size());
+ MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
+ }
+
+ public ArraySet<String> getOptimizablePackages() {
+ ArraySet<String> pkgs = new ArraySet<>();
+ synchronized (mPm.mLock) {
+ for (AndroidPackage p : mPm.mPackages.values()) {
+ if (PackageDexOptimizer.canOptimizePackage(p)) {
+ pkgs.add(p.getPackageName());
+ }
+ }
+ }
+ if (AppHibernationService.isAppHibernationEnabled()) {
+ AppHibernationManagerInternal appHibernationManager =
+ mPm.mInjector.getLocalService(AppHibernationManagerInternal.class);
+ pkgs.removeIf(pkgName -> appHibernationManager.isHibernatingGlobally(pkgName));
+ }
+ return pkgs;
+ }
+
+ /*package*/ boolean performDexOpt(DexoptOptions options) {
+ if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return false;
+ } else if (mPm.isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) {
+ return false;
+ }
+
+ if (options.isDexoptOnlySecondaryDex()) {
+ return mPm.getDexManager().dexoptSecondaryDex(options);
+ } else {
+ int dexoptStatus = performDexOptWithStatus(options);
+ return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
+ }
+ }
+
+ /**
+ * Perform dexopt on the given package and return one of following result:
+ * {@link PackageDexOptimizer#DEX_OPT_SKIPPED}
+ * {@link PackageDexOptimizer#DEX_OPT_PERFORMED}
+ * {@link PackageDexOptimizer#DEX_OPT_CANCELLED}
+ * {@link PackageDexOptimizer#DEX_OPT_FAILED}
+ */
+ @PackageDexOptimizer.DexOptResult
+ /* package */ int performDexOptWithStatus(DexoptOptions options) {
+ return performDexOptTraced(options);
+ }
+
+ private int performDexOptTraced(DexoptOptions options) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ try {
+ return performDexOptInternal(options);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ // Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
+ // if the package can now be considered up to date for the given filter.
+ private int performDexOptInternal(DexoptOptions options) {
+ AndroidPackage p;
+ PackageSetting pkgSetting;
+ synchronized (mPm.mLock) {
+ p = mPm.mPackages.get(options.getPackageName());
+ pkgSetting = mPm.mSettings.getPackageLPr(options.getPackageName());
+ if (p == null || pkgSetting == null) {
+ // Package could not be found. Report failure.
+ return PackageDexOptimizer.DEX_OPT_FAILED;
+ }
+ mPm.getPackageUsage().maybeWriteAsync(mPm.mSettings.getPackagesLocked());
+ mPm.mCompilerStats.maybeWriteAsync();
+ }
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mPm.mInstallLock) {
+ return performDexOptInternalWithDependenciesLI(p, pkgSetting, options);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ private int performDexOptInternalWithDependenciesLI(AndroidPackage p,
+ @NonNull PackageSetting pkgSetting, DexoptOptions options) {
+ // System server gets a special path.
+ if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) {
+ return mPm.getDexManager().dexoptSystemServer(options);
+ }
+
+ // Select the dex optimizer based on the force parameter.
+ // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
+ // allocate an object here.
+ PackageDexOptimizer pdo = options.isForce()
+ ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPm.mPackageDexOptimizer)
+ : mPm.mPackageDexOptimizer;
+
+ // Dexopt all dependencies first. Note: we ignore the return value and march on
+ // on errors.
+ // Note that we are going to call performDexOpt on those libraries as many times as
+ // they are referenced in packages. When we do a batch of performDexOpt (for example
+ // at boot, or background job), the passed 'targetCompilerFilter' stays the same,
+ // and the first package that uses the library will dexopt it. The
+ // others will see that the compiled code for the library is up to date.
+ Collection<SharedLibraryInfo> deps = SharedLibraryHelper.findSharedLibraries(pkgSetting);
+ final String[] instructionSets = getAppDexInstructionSets(
+ AndroidPackageUtils.getPrimaryCpuAbi(p, pkgSetting),
+ AndroidPackageUtils.getSecondaryCpuAbi(p, pkgSetting));
+ if (!deps.isEmpty()) {
+ DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
+ options.getCompilationReason(), options.getCompilerFilter(),
+ options.getSplitName(),
+ options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
+ for (SharedLibraryInfo info : deps) {
+ AndroidPackage depPackage = null;
+ PackageSetting depPackageSetting = null;
+ synchronized (mPm.mLock) {
+ depPackage = mPm.mPackages.get(info.getPackageName());
+ depPackageSetting = mPm.mSettings.getPackageLPr(info.getPackageName());
+ }
+ if (depPackage != null && depPackageSetting != null) {
+ // TODO: Analyze and investigate if we (should) profile libraries.
+ pdo.performDexOpt(depPackage, depPackageSetting, instructionSets,
+ mPm.getOrCreateCompilerPackageStats(depPackage),
+ mPm.getDexManager().getPackageUseInfoOrDefault(
+ depPackage.getPackageName()), libraryOptions);
+ } else {
+ // TODO(ngeoffray): Support dexopting system shared libraries.
+ }
+ }
+ }
+
+ return pdo.performDexOpt(p, pkgSetting, instructionSets,
+ mPm.getOrCreateCompilerPackageStats(p),
+ mPm.getDexManager().getPackageUseInfoOrDefault(p.getPackageName()), options);
+ }
+
+ public void forceDexOpt(String packageName) {
+ PackageManagerServiceUtils.enforceSystemOrRoot("forceDexOpt");
+
+ AndroidPackage pkg;
+ PackageSetting pkgSetting;
+ synchronized (mPm.mLock) {
+ pkg = mPm.mPackages.get(packageName);
+ pkgSetting = mPm.mSettings.getPackageLPr(packageName);
+ if (pkg == null || pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ }
+
+ synchronized (mPm.mInstallLock) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+
+ // Whoever is calling forceDexOpt wants a compiled package.
+ // Don't use profiles since that may cause compilation to be skipped.
+ final int res = performDexOptInternalWithDependenciesLI(pkg, pkgSetting,
+ new DexoptOptions(packageName,
+ getDefaultCompilerFilter(),
+ DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE));
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ throw new IllegalStateException("Failed to dexopt: " + res);
+ }
+ }
+ }
+
+ public boolean performDexOptMode(String packageName,
+ boolean checkProfiles, String targetCompilerFilter, boolean force,
+ boolean bootComplete, String splitName) {
+ PackageManagerServiceUtils.enforceSystemOrRootOrShell("performDexOptMode");
+
+ int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0)
+ | (force ? DexoptOptions.DEXOPT_FORCE : 0)
+ | (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
+ return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE,
+ targetCompilerFilter, splitName, flags));
+ }
+
+ public boolean performDexOptSecondary(String packageName, String compilerFilter,
+ boolean force) {
+ int flags = DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX
+ | DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES
+ | DexoptOptions.DEXOPT_BOOT_COMPLETE
+ | (force ? DexoptOptions.DEXOPT_FORCE : 0);
+ return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags));
+ }
+
+ // Sort apps by importance for dexopt ordering. Important apps are given
+ // more priority in case the device runs out of space.
+ public static List<PackageSetting> getPackagesForDexopt(
+ Collection<PackageSetting> packages,
+ PackageManagerService packageManagerService) {
+ return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
+ }
+
+ public static List<PackageSetting> getPackagesForDexopt(
+ Collection<PackageSetting> pkgSettings,
+ PackageManagerService packageManagerService,
+ boolean debug) {
+ List<PackageSetting> result = new LinkedList<>();
+ ArrayList<PackageSetting> remainingPkgSettings = new ArrayList<>(pkgSettings);
+
+ // First, remove all settings without available packages
+ remainingPkgSettings.removeIf(REMOVE_IF_NULL_PKG);
+
+ ArrayList<PackageSetting> sortTemp = new ArrayList<>(remainingPkgSettings.size());
+
+ // Give priority to core apps.
+ applyPackageFilter(pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
+ remainingPkgSettings, sortTemp, packageManagerService);
+
+ // Give priority to system apps that listen for pre boot complete.
+ Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+ final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
+ applyPackageFilter(pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
+ remainingPkgSettings, sortTemp, packageManagerService);
+
+ // Give priority to apps used by other apps.
+ DexManager dexManager = packageManagerService.getDexManager();
+ applyPackageFilter(pkgSetting ->
+ dexManager.getPackageUseInfoOrDefault(pkgSetting.getPackageName())
+ .isAnyCodePathUsedByOtherApps(),
+ result, remainingPkgSettings, sortTemp, packageManagerService);
+
+ // Filter out packages that aren't recently used, add all remaining apps.
+ // TODO: add a property to control this?
+ Predicate<PackageSetting> remainingPredicate;
+ if (!remainingPkgSettings.isEmpty()
+ && packageManagerService.isHistoricalPackageUsageAvailable()) {
+ if (debug) {
+ Log.i(TAG, "Looking at historical package use");
+ }
+ // Get the package that was used last.
+ PackageSetting lastUsed = Collections.max(remainingPkgSettings,
+ (pkgSetting1, pkgSetting2) -> Long.compare(
+ pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills(),
+ pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills()));
+ if (debug) {
+ Log.i(TAG, "Taking package " + lastUsed.getPackageName()
+ + " as reference in time use");
+ }
+ long estimatedPreviousSystemUseTime = lastUsed.getPkgState()
+ .getLatestForegroundPackageUseTimeInMills();
+ // Be defensive if for some reason package usage has bogus data.
+ if (estimatedPreviousSystemUseTime != 0) {
+ final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
+ remainingPredicate = pkgSetting -> pkgSetting.getPkgState()
+ .getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
+ } else {
+ // No meaningful historical info. Take all.
+ remainingPredicate = pkgSetting -> true;
+ }
+ sortPackagesByUsageDate(remainingPkgSettings, packageManagerService);
+ } else {
+ // No historical info. Take all.
+ remainingPredicate = pkgSetting -> true;
+ }
+ applyPackageFilter(remainingPredicate, result, remainingPkgSettings, sortTemp,
+ packageManagerService);
+
+ if (debug) {
+ Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
+ Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgSettings));
+ }
+
+ return result;
+ }
+
+ // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the
+ // package will be removed from {@code packages} and added to {@code result} with its
+ // dependencies. If usage data is available, the positive packages will be sorted by usage
+ // data (with {@code sortTemp} as temporary storage).
+ private static void applyPackageFilter(
+ Predicate<PackageSetting> filter,
+ Collection<PackageSetting> result,
+ Collection<PackageSetting> packages,
+ @NonNull List<PackageSetting> sortTemp,
+ PackageManagerService packageManagerService) {
+ for (PackageSetting pkgSetting : packages) {
+ if (filter.test(pkgSetting)) {
+ sortTemp.add(pkgSetting);
+ }
+ }
+
+ sortPackagesByUsageDate(sortTemp, packageManagerService);
+ packages.removeAll(sortTemp);
+
+ for (PackageSetting pkgSetting : sortTemp) {
+ result.add(pkgSetting);
+
+ List<PackageSetting> deps =
+ packageManagerService.findSharedNonSystemLibraries(pkgSetting);
+ if (!deps.isEmpty()) {
+ deps.removeAll(result);
+ result.addAll(deps);
+ packages.removeAll(deps);
+ }
+ }
+
+ sortTemp.clear();
+ }
+
+ // Sort a list of apps by their last usage, most recently used apps first. The order of
+ // packages without usage data is undefined (but they will be sorted after the packages
+ // that do have usage data).
+ private static void sortPackagesByUsageDate(List<PackageSetting> pkgSettings,
+ PackageManagerService packageManagerService) {
+ if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
+ return;
+ }
+
+ Collections.sort(pkgSettings, (pkgSetting1, pkgSetting2) ->
+ Long.compare(
+ pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills(),
+ pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills())
+ );
+ }
+
+ private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
+ List<ResolveInfo> ris = null;
+ try {
+ ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId)
+ .getList();
+ } catch (RemoteException e) {
+ }
+ ArraySet<String> pkgNames = new ArraySet<String>();
+ if (ris != null) {
+ for (ResolveInfo ri : ris) {
+ pkgNames.add(ri.activityInfo.packageName);
+ }
+ }
+ return pkgNames;
+ }
+
+ public static String packagesToString(List<PackageSetting> pkgSettings) {
+ StringBuilder sb = new StringBuilder();
+ for (int index = 0; index < pkgSettings.size(); index++) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(pkgSettings.get(index).getPackageName());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Requests that files preopted on a secondary system partition be copied to the data partition
+ * if possible. Note that the actual copying of the files is accomplished by init for security
+ * reasons. This simply requests that the copy takes place and awaits confirmation of its
+ * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy.
+ */
+ public static void requestCopyPreoptedFiles() {
+ final int WAIT_TIME_MS = 100;
+ final String CP_PREOPT_PROPERTY = "sys.cppreopt";
+ if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
+ SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
+ // We will wait for up to 100 seconds.
+ final long timeStart = SystemClock.uptimeMillis();
+ final long timeEnd = timeStart + 100 * 1000;
+ long timeNow = timeStart;
+ while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
+ try {
+ Thread.sleep(WAIT_TIME_MS);
+ } catch (InterruptedException e) {
+ // Do nothing
+ }
+ timeNow = SystemClock.uptimeMillis();
+ if (timeNow > timeEnd) {
+ SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
+ Slog.wtf(TAG, "cppreopt did not finish!");
+ break;
+ }
+ }
+
+ Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms");
+ }
+ }
+
+ /*package*/ void controlDexOptBlocking(boolean block) {
+ mPm.mPackageDexOptimizer.controlDexOptBlocking(block);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index 9ba69f8..722198f 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -35,8 +35,12 @@
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;
+import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
+import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
+import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
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;
@@ -55,6 +59,7 @@
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;
@@ -62,6 +67,7 @@
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;
import com.android.server.EventLogTags;
@@ -90,60 +96,129 @@
private final RemovePackageHelper mRemovePackageHelper;
private final AppDataHelper mAppDataHelper;
+ private final List<ScanPartition> mDirsToScanAsSystem;
+ private final int mScanFlags;
+ private final int mSystemParseFlags;
+ private final int mSystemScanFlags;
+
+ /**
+ * Tracks new system packages [received in an OTA] that we expect to
+ * find updated user-installed versions. Keys are package name, values
+ * are package location.
+ */
+ private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+
// TODO(b/198166813): remove PMS dependency
InitAndSystemPackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper,
AppDataHelper appDataHelper) {
mPm = pm;
mRemovePackageHelper = removePackageHelper;
mAppDataHelper = appDataHelper;
+ mDirsToScanAsSystem = getSystemScanPartitions();
+ // Set flag to monitor and not change apk file paths when scanning install directories.
+ int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
+ if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
+ mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
+ } else {
+ mScanFlags = scanFlags;
+ }
+ mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
+ mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
}
+ private List<ScanPartition> getSystemScanPartitions() {
+ final List<ScanPartition> scanPartitions = new ArrayList<>();
+ scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
+ scanPartitions.addAll(getApexScanPartitions());
+ Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
+ return scanPartitions;
+ }
+
+ private List<ScanPartition> getApexScanPartitions() {
+ final List<ScanPartition> scanPartitions = new ArrayList<>();
+ final List<ApexManager.ActiveApexInfo> activeApexInfos =
+ mPm.mApexManager.getActiveApexInfos();
+ for (int i = 0; i < activeApexInfos.size(); i++) {
+ final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
+ if (scanPartition != null) {
+ scanPartitions.add(scanPartition);
+ }
+ }
+ return scanPartitions;
+ }
+
+ private static @Nullable ScanPartition resolveApexToScanPartition(
+ ApexManager.ActiveApexInfo apexInfo) {
+ for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
+ ScanPartition sp = SYSTEM_PARTITIONS.get(i);
+ if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
+ sp.getFolder().getAbsolutePath())) {
+ return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
+ }
+ }
+ return null;
+ }
+
+ public OverlayConfig setUpSystemPackages(
+ WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
+ long startTime) {
+ PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
+
+ ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+ // Prepare apex package info before scanning APKs, these information are needed when
+ // scanning apk in apex.
+ mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
+
+ scanSystemDirs(packageParser, executorService);
+ // Parse overlay configuration files to set default enable state, mutability, and
+ // priority of system overlays.
+ OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+ consumer -> mPm.forEachPackage(
+ pkg -> consumer.accept(pkg, pkg.isSystem())));
+ cleanupSystemPackagesAndInstallStubs(packageParser, executorService, packageSettings,
+ startTime, userIds);
+ packageParser.close();
+ return overlayConfig;
+ }
/**
* First part of init dir scanning
*/
- // TODO(b/197876467): consolidate this with cleanupSystemPackagesAndInstallStubs
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- public void scanSystemDirs(List<ScanPartition> dirsToScanAsSystem,
- boolean isUpgrade, PackageParser2 packageParser,
- ExecutorService executorService, AndroidPackage platformPackage,
- boolean isPreNMR1Upgrade, int systemParseFlags, int systemScanFlags) {
+ private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// Collect vendor/product/system_ext overlay packages. (Do this before scanning
// any apps.)
// For security and version matching reason, only consider overlay packages if they
// reside in the right directory.
- for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
- final ScanPartition partition = dirsToScanAsSystem.get(i);
+ for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
+ final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getOverlayFolder() == null) {
continue;
}
- scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
- systemScanFlags | partition.scanFlag, 0,
- packageParser, executorService, platformPackage, isUpgrade,
- isPreNMR1Upgrade);
+ scanDirTracedLI(partition.getOverlayFolder(), mSystemParseFlags,
+ mSystemScanFlags | partition.scanFlag, 0,
+ packageParser, executorService);
}
- scanDirTracedLI(frameworkDir, systemParseFlags,
- systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
- packageParser, executorService, platformPackage, isUpgrade, isPreNMR1Upgrade);
+ scanDirTracedLI(frameworkDir, mSystemParseFlags,
+ mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+ packageParser, executorService);
if (!mPm.mPackages.containsKey("android")) {
throw new IllegalStateException(
"Failed to load frameworks package; check log for warnings");
}
- for (int i = 0, size = dirsToScanAsSystem.size(); i < size; i++) {
- final ScanPartition partition = dirsToScanAsSystem.get(i);
+ for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
+ final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getPrivAppFolder() != null) {
- scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
- systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
- packageParser, executorService, platformPackage, isUpgrade,
- isPreNMR1Upgrade);
+ scanDirTracedLI(partition.getPrivAppFolder(), mSystemParseFlags,
+ mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+ packageParser, executorService);
}
- scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
- systemScanFlags | partition.scanFlag, 0,
- packageParser, executorService, platformPackage, isUpgrade,
- isPreNMR1Upgrade);
+ scanDirTracedLI(partition.getAppFolder(), mSystemParseFlags,
+ mSystemScanFlags | partition.scanFlag, 0,
+ packageParser, executorService);
}
}
@@ -151,20 +226,17 @@
* Second part of init dir scanning
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- public void cleanupSystemPackagesAndInstallStubs(List<ScanPartition> dirsToScanAsSystem,
- boolean isUpgrade, PackageParser2 packageParser,
- ExecutorService executorService, boolean onlyCore,
+ private void cleanupSystemPackagesAndInstallStubs(PackageParser2 packageParser,
+ ExecutorService executorService,
WatchedArrayMap<String, PackageSetting> packageSettings,
- long startTime, File appInstallDir, AndroidPackage platformPackage,
- boolean isPreNMR1Upgrade, int scanFlags, int systemParseFlags, int systemScanFlags,
- int[] userIds) {
+ long startTime, int[] userIds) {
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
// Stub packages must either be replaced with full versions in the /data
// partition or be disabled.
final List<String> stubSystemApps = new ArrayList<>();
- if (!onlyCore) {
+ if (!mPm.isOnlyCoreApps()) {
// do this first before mucking with mPackages for the "expecting better" case
final int numPackages = mPm.mPackages.size();
for (int index = 0; index < numPackages; index++) {
@@ -209,7 +281,7 @@
+ "; scanned versionCode="
+ scannedPkg.getLongVersionCode());
mRemovePackageHelper.removePackageLI(scannedPkg, true);
- mPm.mExpectingBetter.put(ps.getPackageName(), ps.getPath());
+ mExpectingBetter.put(ps.getPackageName(), ps.getPath());
}
continue;
@@ -233,9 +305,7 @@
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
- // TODO(b/197869066): mExpectingBetter should be able to pulled out into
- // this class and used only by the PMS initialization
- mPm.mExpectingBetter.put(disabledPs.getPackageName(), disabledPs.getPath());
+ mExpectingBetter.put(disabledPs.getPackageName(), disabledPs.getPath());
}
}
}
@@ -252,19 +322,18 @@
+ " , timePerPackage: "
+ (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+ " , cached: " + cachedSystemApps);
- if (isUpgrade && systemPackagesCount > 0) {
+ if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
systemScanTime / systemPackagesCount);
//CHECKSTYLE:ON IndentationCheck
}
- if (!onlyCore) {
+ if (!mPm.isOnlyCoreApps()) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirTracedLI(appInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
- packageParser, executorService, platformPackage, isUpgrade,
- isPreNMR1Upgrade);
+ scanDirTracedLI(mPm.getAppInstallDir(), 0, mScanFlags | SCAN_REQUIRE_KNOWN, 0,
+ packageParser, executorService);
}
@@ -274,7 +343,7 @@
+ unfinishedTasks);
}
- if (!onlyCore) {
+ if (!mPm.isOnlyCoreApps()) {
final ScanPackageHelper scanPackageHelper = new ScanPackageHelper(mPm);
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
@@ -308,7 +377,7 @@
mRemovePackageHelper.removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getPath());
- scanPackageHelper.scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
+ scanPackageHelper.scanPackageTracedLI(codePath, 0, mScanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
@@ -332,27 +401,27 @@
* the userdata partition actually showed up. If they never
* appeared, crawl back and revive the system version.
*/
- for (int i = 0; i < mPm.mExpectingBetter.size(); i++) {
- final String packageName = mPm.mExpectingBetter.keyAt(i);
+ for (int i = 0; i < mExpectingBetter.size(); i++) {
+ final String packageName = mExpectingBetter.keyAt(i);
if (!mPm.mPackages.containsKey(packageName)) {
- final File scanFile = mPm.mExpectingBetter.valueAt(i);
+ final File scanFile = mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
@ParsingPackageUtils.ParseFlags int reparseFlags = 0;
@PackageManagerService.ScanFlags int rescanFlags = 0;
- for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
- final ScanPartition partition = dirsToScanAsSystem.get(i1);
+ for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
+ final ScanPartition partition = mDirsToScanAsSystem.get(i1);
if (partition.containsPrivApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
+ reparseFlags = mSystemParseFlags;
+ rescanFlags = mSystemScanFlags | SCAN_AS_PRIVILEGED
| partition.scanFlag;
break;
}
if (partition.containsApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | partition.scanFlag;
+ reparseFlags = mSystemParseFlags;
+ rescanFlags = mSystemScanFlags | partition.scanFlag;
break;
}
}
@@ -378,7 +447,7 @@
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
- installSystemStubPackages(stubSystemApps, scanFlags);
+ installSystemStubPackages(stubSystemApps, mScanFlags);
final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- cachedSystemApps;
@@ -390,7 +459,7 @@
+ " , timePerPackage: "
+ (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ " , cached: " + cachedNonSystemApps);
- if (isUpgrade && dataPackagesCount > 0) {
+ if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(
FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
@@ -399,19 +468,17 @@
//CHECKSTYLE:OFF IndentationCheck
}
}
- mPm.mExpectingBetter.clear();
+ mExpectingBetter.clear();
mPm.mSettings.pruneRenamedPackagesLPw();
}
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
- long currentTime, PackageParser2 packageParser, ExecutorService executorService,
- AndroidPackage platformPackage, boolean isUpgrade, boolean isPreNMR1Upgrade) {
+ long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
- scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService,
- platformPackage, isUpgrade, isPreNMR1Upgrade);
+ scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -419,8 +486,7 @@
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
- PackageParser2 packageParser, ExecutorService executorService,
- AndroidPackage platformPackage, boolean isUpgrade, boolean isPreNMR1Upgrade) {
+ PackageParser2 packageParser, ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + scanDir);
@@ -465,8 +531,7 @@
}
try {
scanPackageHelper.addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
- currentTime, null, platformPackage, isUpgrade,
- isPreNMR1Upgrade);
+ currentTime, null);
} catch (PackageManagerException e) {
errorCode = e.error;
errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
@@ -564,9 +629,8 @@
*/
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
public boolean enableCompressedPackage(AndroidPackage stubPkg,
- @NonNull PackageSetting stubPkgSetting, int defParseFlags,
- List<ScanPartition> dirsToScanAsSystem) {
- final int parseFlags = defParseFlags | ParsingPackageUtils.PARSE_CHATTY
+ @NonNull PackageSetting stubPkgSetting) {
+ final int parseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_CHATTY
| ParsingPackageUtils.PARSE_ENFORCE_CODE;
synchronized (mPm.mInstallLock) {
final AndroidPackage pkg;
@@ -599,7 +663,7 @@
installPackageFromSystemLIF(stubPkg.getPath(),
mPm.mUserManager.getUserIds() /*allUserHandles*/,
null /*origUserHandles*/,
- true /*writeSettings*/, defParseFlags, dirsToScanAsSystem);
+ 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(),
@@ -715,7 +779,7 @@
// 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.mSystemReady) {
+ if (!mPm.isSystemReady()) {
if (mPm.mReleaseOnSystemReady == null) {
mPm.mReleaseOnSystemReady = new ArrayList<>();
}
@@ -749,7 +813,7 @@
public void restoreDisabledSystemPackageLIF(DeletePackageAction action,
PackageSetting deletedPs, @NonNull int[] allUserHandles,
@Nullable PackageRemovedInfo outInfo,
- boolean writeSettings, int defParseFlags, List<ScanPartition> dirsToScanAsSystem,
+ boolean writeSettings,
PackageSetting disabledPs)
throws SystemDeleteException {
// writer
@@ -768,8 +832,7 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
- outInfo == null ? null : outInfo.mOrigUsers, writeSettings, defParseFlags,
- dirsToScanAsSystem);
+ outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPs.getPackageName() + ": "
+ e.getMessage());
@@ -808,17 +871,16 @@
*/
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private void installPackageFromSystemLIF(@NonNull String codePathString,
- @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings,
- int defParseFlags, List<ScanPartition> dirsToScanAsSystem)
+ @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
throws PackageManagerException {
final File codePath = new File(codePathString);
@ParsingPackageUtils.ParseFlags int parseFlags =
- defParseFlags
+ mPm.getDefParseFlags()
| ParsingPackageUtils.PARSE_MUST_BE_APK
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
- for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
- ScanPartition partition = dirsToScanAsSystem.get(i);
+ 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)) {
@@ -894,4 +956,8 @@
}
}
}
+
+ public boolean isExpectingBetter(String packageName) {
+ return mExpectingBetter.containsKey(packageName);
+ }
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index cb390f0..7569900 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -38,12 +38,9 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.backup.IBackupManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.DataLoaderType;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -53,7 +50,6 @@
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ComponentMutateUtils;
import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.pkg.PackageUserState;
import android.os.Binder;
import android.os.Message;
import android.os.Process;
@@ -67,11 +63,8 @@
import android.util.Log;
import android.util.Slog;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.ResolverActivity;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -478,46 +471,11 @@
final String pkgName = pkg.getPackageName();
if (mPm.mCustomResolverComponentName != null
&& mPm.mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
- setUpCustomResolverActivity(pkg, pkgSetting);
+ mPm.setUpCustomResolverActivity(pkg, pkgSetting);
}
if (pkg.getPackageName().equals("android")) {
- synchronized (mPm.mLock) {
- // Set up information for our fall-back user intent resolution activity.
- mPm.mPlatformPackage = pkg;
-
- // The instance stored in PackageManagerService is special cased to be non-user
- // specific, so initialize all the needed fields here.
- mPm.mAndroidApplication = PackageInfoUtils.generateApplicationInfo(pkg, 0,
- PackageUserState.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting);
-
- if (!mPm.mResolverReplaced) {
- mPm.mResolveActivity.applicationInfo = mPm.mAndroidApplication;
- mPm.mResolveActivity.name = ResolverActivity.class.getName();
- mPm.mResolveActivity.packageName = mPm.mAndroidApplication.packageName;
- mPm.mResolveActivity.processName = "system:ui";
- mPm.mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- mPm.mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
- mPm.mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
- mPm.mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
- mPm.mResolveActivity.exported = true;
- mPm.mResolveActivity.enabled = true;
- mPm.mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- mPm.mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_ORIENTATION
- | ActivityInfo.CONFIG_KEYBOARD
- | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
- mPm.mResolveInfo.activityInfo = mPm.mResolveActivity;
- mPm.mResolveInfo.priority = 0;
- mPm.mResolveInfo.preferredOrder = 0;
- mPm.mResolveInfo.match = 0;
- mPm.mResolveComponentName = new ComponentName(
- mPm.mAndroidApplication.packageName, mPm.mResolveActivity.name);
- }
- PackageManagerService.onChanged();
- }
+ mPm.setPlatformPackage(pkg, pkgSetting);
}
ArrayList<AndroidPackage> clientLibPkgs = null;
@@ -633,37 +591,6 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private void setUpCustomResolverActivity(AndroidPackage pkg, PackageSetting pkgSetting) {
- synchronized (mPm.mLock) {
- mPm.mResolverReplaced = true;
-
- // The instance created in PackageManagerService is special cased to be non-user
- // specific, so initialize all the needed fields here.
- ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0,
- PackageUserState.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting);
-
- // Set up information for custom user intent resolution activity.
- mPm.mResolveActivity.applicationInfo = appInfo;
- mPm.mResolveActivity.name = mPm.mCustomResolverComponentName.getClassName();
- mPm.mResolveActivity.packageName = pkg.getPackageName();
- mPm.mResolveActivity.processName = pkg.getProcessName();
- mPm.mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- mPm.mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
- | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
- mPm.mResolveActivity.theme = 0;
- mPm.mResolveActivity.exported = true;
- mPm.mResolveActivity.enabled = true;
- mPm.mResolveInfo.activityInfo = mPm.mResolveActivity;
- mPm.mResolveInfo.priority = 0;
- mPm.mResolveInfo.preferredOrder = 0;
- mPm.mResolveInfo.match = 0;
- mPm.mResolveComponentName = mPm.mCustomResolverComponentName;
- PackageManagerService.onChanged();
- Slog.i(TAG, "Replacing default ResolverActivity with custom activity: "
- + mPm.mResolveComponentName);
- }
- }
-
/**
* If the database version for this type of package (internal storage or
* external storage) is less than the version where package signatures
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
index cf10f34..bfb5f76 100644
--- a/services/core/java/com/android/server/pm/InstallParams.java
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -734,7 +734,7 @@
// Retrieve PackageSettings and parse package
@ParsingPackageUtils.ParseFlags final int parseFlags =
- mPm.mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
+ mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_CHATTY
| ParsingPackageUtils.PARSE_ENFORCE_CODE
| (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0);
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 9595e15..68801d6 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -128,7 +128,7 @@
PLATFORM_PACKAGE_NAME.equals(pkgSetting.getPkg().getPackageName());
synchronized (mPackageManagerService.mLock) {
// Important: the packages we need to run with ab-ota compiler-reason.
- important = PackageManagerServiceUtils.getPackagesForDexopt(
+ important = DexOptHelper.getPackagesForDexopt(
mPackageManagerService.mSettings.getPackagesLocked().values(),
mPackageManagerService, DEBUG_DEXOPT);
// Remove Platform Package from A/B OTA b/160735835.
@@ -160,7 +160,7 @@
long spaceAvailable = getAvailableSpace();
if (spaceAvailable < BULK_DELETE_THRESHOLD) {
Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
- + PackageManagerServiceUtils.packagesToString(others));
+ + DexOptHelper.packagesToString(others));
for (PackageSetting pkg : others) {
mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerNative.java b/services/core/java/com/android/server/pm/PackageManagerNative.java
new file mode 100644
index 0000000..37daf11
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerNative.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
+
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageChangeObserver;
+import android.content.pm.IPackageManagerNative;
+import android.content.pm.IStagedApexObserver;
+import android.content.pm.PackageInfo;
+import android.content.pm.StagedApexInfo;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+
+import java.util.Arrays;
+
+final class PackageManagerNative extends IPackageManagerNative.Stub {
+ private final PackageManagerService mPm;
+
+ PackageManagerNative(PackageManagerService pm) {
+ mPm = pm;
+ }
+
+ @Override
+ public void registerPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
+ synchronized (mPm.mPackageChangeObservers) {
+ try {
+ observer.asBinder().linkToDeath(
+ new PackageChangeObserverDeathRecipient(observer), 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ mPm.mPackageChangeObservers.add(observer);
+ Log.d(TAG, "Size of mPackageChangeObservers after registry is "
+ + mPm.mPackageChangeObservers.size());
+ }
+ }
+
+ @Override
+ public void unregisterPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
+ synchronized (mPm.mPackageChangeObservers) {
+ mPm.mPackageChangeObservers.remove(observer);
+ Log.d(TAG, "Size of mPackageChangeObservers after unregistry is "
+ + mPm.mPackageChangeObservers.size());
+ }
+ }
+
+ @Override
+ public String[] getAllPackages() {
+ return mPm.getAllPackages().toArray(new String[0]);
+ }
+
+ @Override
+ public String[] getNamesForUids(int[] uids) throws RemoteException {
+ String[] names = null;
+ String[] results = null;
+ try {
+ if (uids == null || uids.length == 0) {
+ return null;
+ }
+ names = mPm.getNamesForUids(uids);
+ results = (names != null) ? names : new String[uids.length];
+ // massage results so they can be parsed by the native binder
+ for (int i = results.length - 1; i >= 0; --i) {
+ if (results[i] == null) {
+ results[i] = "";
+ }
+ }
+ return results;
+ } catch (Throwable t) {
+ // STOPSHIP(186558987): revert addition of try/catch/log
+ Slog.e(TAG, "uids: " + Arrays.toString(uids));
+ Slog.e(TAG, "names: " + Arrays.toString(names));
+ Slog.e(TAG, "results: " + Arrays.toString(results));
+ Slog.e(TAG, "throwing exception", t);
+ throw t;
+ }
+ }
+
+ // NB: this differentiates between preloads and sideloads
+ @Override
+ public String getInstallerForPackage(String packageName) throws RemoteException {
+ final String installerName = mPm.getInstallerPackageName(packageName);
+ if (!TextUtils.isEmpty(installerName)) {
+ return installerName;
+ }
+ // differentiate between preload and sideload
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ ApplicationInfo appInfo = mPm.getApplicationInfo(packageName,
+ /*flags*/ 0,
+ /*userId*/ callingUser);
+ if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return "preload";
+ }
+ return "";
+ }
+
+ @Override
+ public long getVersionCodeForPackage(String packageName) throws RemoteException {
+ try {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ PackageInfo pInfo = mPm.getPackageInfo(packageName, 0, callingUser);
+ if (pInfo != null) {
+ return pInfo.getLongVersionCode();
+ }
+ } catch (Exception e) {
+ }
+ return 0;
+ }
+
+ @Override
+ public int getTargetSdkVersionForPackage(String packageName) throws RemoteException {
+ int targetSdk = mPm.getTargetSdkVersion(packageName);
+ if (targetSdk != -1) {
+ return targetSdk;
+ }
+
+ throw new RemoteException("Couldn't get targetSdkVersion for package " + packageName);
+ }
+
+ @Override
+ public boolean isPackageDebuggable(String packageName) throws RemoteException {
+ int callingUser = UserHandle.getCallingUserId();
+ ApplicationInfo appInfo = mPm.getApplicationInfo(packageName, 0, callingUser);
+ if (appInfo != null) {
+ return (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE));
+ }
+
+ throw new RemoteException("Couldn't get debug flag for package " + packageName);
+ }
+
+ @Override
+ public boolean[] isAudioPlaybackCaptureAllowed(String[] packageNames)
+ throws RemoteException {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ boolean[] results = new boolean[packageNames.length];
+ for (int i = results.length - 1; i >= 0; --i) {
+ ApplicationInfo appInfo = mPm.getApplicationInfo(packageNames[i], 0, callingUser);
+ results[i] = appInfo != null && appInfo.isAudioPlaybackCaptureAllowed();
+ }
+ return results;
+ }
+
+ @Override
+ public int getLocationFlags(String packageName) throws RemoteException {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ ApplicationInfo appInfo = mPm.getApplicationInfo(packageName,
+ /*flags*/ 0,
+ /*userId*/ callingUser);
+ if (appInfo == null) {
+ throw new RemoteException(
+ "Couldn't get ApplicationInfo for package " + packageName);
+ }
+ return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0)
+ | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
+ | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0));
+ }
+
+ @Override
+ public String getModuleMetadataPackageName() throws RemoteException {
+ return mPm.getModuleMetadataPackageName();
+ }
+
+ @Override
+ public boolean hasSha256SigningCertificate(String packageName, byte[] certificate)
+ throws RemoteException {
+ return mPm.hasSigningCertificate(packageName, certificate, CERT_INPUT_SHA256);
+ }
+
+ @Override
+ public boolean hasSystemFeature(String featureName, int version) {
+ return mPm.hasSystemFeature(featureName, version);
+ }
+
+ @Override
+ public void registerStagedApexObserver(IStagedApexObserver observer) {
+ mPm.mInstallerService.getStagingManager().registerStagedApexObserver(observer);
+ }
+
+ @Override
+ public void unregisterStagedApexObserver(IStagedApexObserver observer) {
+ mPm.mInstallerService.getStagingManager().unregisterStagedApexObserver(observer);
+ }
+
+ @Override
+ public String[] getStagedApexModuleNames() {
+ return mPm.mInstallerService.getStagingManager()
+ .getStagedApexModuleNames().toArray(new String[0]);
+ }
+
+ @Override
+ @Nullable
+ public StagedApexInfo getStagedApexInfo(String moduleName) {
+ return mPm.mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
+ }
+
+ private final class PackageChangeObserverDeathRecipient implements IBinder.DeathRecipient {
+ private final IPackageChangeObserver mObserver;
+
+ PackageChangeObserverDeathRecipient(IPackageChangeObserver observer) {
+ mObserver = observer;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mPm.mPackageChangeObservers) {
+ mPm.mPackageChangeObservers.remove(mObserver);
+ Log.d(TAG, "Size of mPackageChangeObservers after removing dead observer is "
+ + mPm.mPackageChangeObservers.size());
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 192bd43..3eaa26e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -48,10 +48,8 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
-import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
@@ -100,10 +98,8 @@
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.IPackageManager;
-import android.content.pm.IPackageManagerNative;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
-import android.content.pm.IStagedApexObserver;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
@@ -137,13 +133,11 @@
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
-import android.content.pm.StagedApexInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
-import android.content.pm.dex.ArtManager;
import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ParsingPackageUtils;
@@ -216,10 +210,10 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ResolverActivity;
import com.android.internal.content.F2fsUtils;
import com.android.internal.content.PackageHelper;
import com.android.internal.content.om.OverlayConfig;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -238,7 +232,6 @@
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
import com.android.server.apphibernation.AppHibernationManagerInternal;
-import com.android.server.apphibernation.AppHibernationService;
import com.android.server.compat.CompatChange;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.Installer.InstallerException;
@@ -246,7 +239,6 @@
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.ArtUtils;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageCacher;
@@ -300,7 +292,6 @@
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -312,9 +303,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
@@ -388,9 +377,6 @@
static final boolean DEBUG_ABI_SELECTION = false;
public static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
- /** REMOVE. According to Svet, this was only used to reset permissions during development. */
- static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
-
static final boolean HIDE_EPHEMERAL_APIS = false;
static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
@@ -457,40 +443,40 @@
PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface PackageStartability {}
+ private @interface PackageStartability {}
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is allowed to start.
*/
- static final int PACKAGE_STARTABILITY_OK = 0;
+ private static final int PACKAGE_STARTABILITY_OK = 0;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is <b>not</b> allowed to start because it's not found
* (could be due to that package is invisible to the given user).
*/
- static final int PACKAGE_STARTABILITY_NOT_FOUND = 1;
+ private static final int PACKAGE_STARTABILITY_NOT_FOUND = 1;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is <b>not</b> allowed to start because it's not a system app
* and the system is running in safe mode.
*/
- static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2;
+ private static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is <b>not</b> allowed to start because it's currently frozen.
*/
- static final int PACKAGE_STARTABILITY_FROZEN = 3;
+ private static final int PACKAGE_STARTABILITY_FROZEN = 3;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is <b>not</b> allowed to start because it doesn't support
* direct boot.
*/
- static final int PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED = 4;
+ private static final int PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED = 4;
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
/** Extension of the compressed packages */
@@ -585,19 +571,6 @@
public static final int REASON_LAST = REASON_SHARED;
- /**
- * The initial enabled state of the cache before other checks are done.
- */
- private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
-
- /**
- * Whether to skip all other checks and force the cache to be enabled.
- *
- * Setting this to true will cause the cache to be named "debug" to avoid eviction from
- * build fingerprint changes.
- */
- private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false;
-
static final String RANDOM_DIR_PREFIX = "~~";
final Handler mHandler;
@@ -609,17 +582,14 @@
private final int mSdkVersion;
final Context mContext;
final boolean mFactoryTest;
- final boolean mOnlyCore;
+ private final boolean mOnlyCore;
final DisplayMetrics mMetrics;
- final int mDefParseFlags;
- final String[] mSeparateProcesses;
- final boolean mIsUpgrade;
- final boolean mIsPreNUpgrade;
- final boolean mIsPreNMR1Upgrade;
- final boolean mIsPreQUpgrade;
-
- @GuardedBy("mLock")
- private boolean mDexOptDialogShown;
+ private final int mDefParseFlags;
+ private final String[] mSeparateProcesses;
+ private final boolean mIsUpgrade;
+ private final boolean mIsPreNUpgrade;
+ private final boolean mIsPreNMR1Upgrade;
+ private final boolean mIsPreQUpgrade;
// Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
// LOCK HELD. Can be called with mInstallLock held.
@@ -667,13 +637,6 @@
"PackageManagerService.mIsolatedOwners");
/**
- * Tracks new system packages [received in an OTA] that we expect to
- * find updated user-installed versions. Keys are package name, values
- * are package location.
- */
- final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
-
- /**
* Tracks existing packages prior to receiving an OTA. Keys are package name.
* Only non-null during an OTA, and even then it is nulled again once systemReady().
*/
@@ -719,7 +682,7 @@
@GuardedBy("mLoadedVolumes")
final ArraySet<String> mLoadedVolumes = new ArraySet<>();
- boolean mFirstBoot;
+ private boolean mFirstBoot;
final boolean mIsEngBuild;
private final boolean mIsUserDebugBuild;
@@ -765,12 +728,10 @@
public static final List<ScanPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
PackagePartitions.getOrderedPartitions(ScanPartition::new));
- private final List<ScanPartition> mDirsToScanAsSystem;
-
- final OverlayConfig mOverlayConfig;
+ private @NonNull final OverlayConfig mOverlayConfig;
@GuardedBy("itself")
- final private ArrayList<IPackageChangeObserver> mPackageChangeObservers =
+ final ArrayList<IPackageChangeObserver> mPackageChangeObservers =
new ArrayList<>();
// Cached parsed flag value. Invalidated on each flag change.
@@ -877,7 +838,7 @@
int mPendingEnableRollbackToken = 0;
@Watched(manual = true)
- volatile boolean mSystemReady;
+ private volatile boolean mSystemReady;
@Watched(manual = true)
private volatile boolean mSafeMode;
@Watched
@@ -885,16 +846,16 @@
new WatchedSparseBooleanArray();
@Watched(manual = true)
- ApplicationInfo mAndroidApplication;
+ private ApplicationInfo mAndroidApplication;
@Watched(manual = true)
- final ActivityInfo mResolveActivity = new ActivityInfo();
- final ResolveInfo mResolveInfo = new ResolveInfo();
+ private final ActivityInfo mResolveActivity = new ActivityInfo();
+ private final ResolveInfo mResolveInfo = new ResolveInfo();
@Watched(manual = true)
ComponentName mResolveComponentName;
- AndroidPackage mPlatformPackage;
+ private AndroidPackage mPlatformPackage;
ComponentName mCustomResolverComponentName;
- boolean mResolverReplaced = false;
+ private boolean mResolverReplaced = false;
@NonNull
final DomainVerificationManagerInternal mDomainVerificationManager;
@@ -1011,6 +972,7 @@
private final AppDataHelper mAppDataHelper;
private final PreferredActivityHelper mPreferredActivityHelper;
private final ResolveIntentHelper mResolveIntentHelper;
+ private final DexOptHelper mDexOptHelper;
/**
* Invalidate the package info cache, which includes updating the cached computer.
@@ -1540,7 +1502,7 @@
m.installAllowlistedSystemPackages();
ServiceManager.addService("package", m);
- final PackageManagerNative pmn = m.new PackageManagerNative();
+ final PackageManagerNative pmn = new PackageManagerNative(m);
ServiceManager.addService("package_native", pmn);
return m;
}
@@ -1557,39 +1519,6 @@
}
}
- /**
- * Requests that files preopted on a secondary system partition be copied to the data partition
- * if possible. Note that the actual copying of the files is accomplished by init for security
- * reasons. This simply requests that the copy takes place and awaits confirmation of its
- * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy.
- */
- private static void requestCopyPreoptedFiles() {
- final int WAIT_TIME_MS = 100;
- final String CP_PREOPT_PROPERTY = "sys.cppreopt";
- if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
- SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
- // We will wait for up to 100 seconds.
- final long timeStart = SystemClock.uptimeMillis();
- final long timeEnd = timeStart + 100 * 1000;
- long timeNow = timeStart;
- while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
- try {
- Thread.sleep(WAIT_TIME_MS);
- } catch (InterruptedException e) {
- // Do nothing
- }
- timeNow = SystemClock.uptimeMillis();
- if (timeNow > timeEnd) {
- SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
- Slog.wtf(TAG, "cppreopt did not finish!");
- break;
- }
- }
-
- Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms");
- }
- }
-
// Link watchables to the class
private void registerObserver() {
mPackages.registerObserver(mWatcher);
@@ -1639,7 +1568,6 @@
mDefaultAppProvider = testParams.defaultAppProvider;
mLegacyPermissionManager = testParams.legacyPermissionManagerInternal;
mDexManager = testParams.dexManager;
- mDirsToScanAsSystem = testParams.dirsToScanAsSystem;
mFactoryTest = testParams.factoryTest;
mIncrementalManager = testParams.incrementalManager;
mInstallerService = testParams.installerService;
@@ -1700,15 +1628,14 @@
mIncrementalVersion = testParams.incrementalVersion;
mDomainVerificationConnection = new DomainVerificationConnection(this);
- mBroadcastHelper = new BroadcastHelper(mInjector);
- mAppDataHelper = new AppDataHelper(this);
- mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper,
- mAppDataHelper);
- mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
- mInitAndSystemPackageHelper, mAppDataHelper);
- mPreferredActivityHelper = new PreferredActivityHelper(this);
- mResolveIntentHelper = new ResolveIntentHelper(this, mPreferredActivityHelper);
+ mBroadcastHelper = testParams.broadcastHelper;
+ mAppDataHelper = testParams.appDataHelper;
+ mRemovePackageHelper = testParams.removePackageHelper;
+ mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
+ mDeletePackageHelper = testParams.deletePackageHelper;
+ mPreferredActivityHelper = testParams.preferredActivityHelper;
+ mResolveIntentHelper = testParams.resolveIntentHelper;
+ mDexOptHelper = testParams.dexOptHelper;
invalidatePackageInfoCache();
}
@@ -1831,22 +1758,8 @@
mApexManager = injector.getApexManager();
mAppsFilter = mInjector.getAppsFilter();
- final List<ScanPartition> scanPartitions = new ArrayList<>();
- final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
- for (int i = 0; i < activeApexInfos.size(); i++) {
- final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
- if (scanPartition != null) {
- scanPartitions.add(scanPartition);
- }
- }
-
mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager, mPmInternal);
- mDirsToScanAsSystem = new ArrayList<>();
- mDirsToScanAsSystem.addAll(injector.getSystemPartitions());
- mDirsToScanAsSystem.addAll(scanPartitions);
- Slog.d(TAG, "Directories scanned as system partitions: " + mDirsToScanAsSystem);
-
mAppInstallDir = new File(Environment.getDataDirectory(), "app");
mAppLib32InstallDir = getAppLib32InstallDir();
@@ -1863,6 +1776,7 @@
mInitAndSystemPackageHelper, mAppDataHelper);
mPreferredActivityHelper = new PreferredActivityHelper(this);
mResolveIntentHelper = new ResolveIntentHelper(this, mPreferredActivityHelper);
+ mDexOptHelper = new DexOptHelper(this);
synchronized (mLock) {
// Create the computer as soon as the state objects have been installed. The
@@ -1927,7 +1841,7 @@
mPermissionManager.readLegacyPermissionStateTEMP();
if (!mOnlyCore && mFirstBoot) {
- requestCopyPreoptedFiles();
+ DexOptHelper.requestCopyPreoptedFiles();
}
String customResolverActivityName = Resources.getSystem().getString(
@@ -1984,40 +1898,12 @@
}
}
- mCacheDir = preparePackageParserCache(mIsEngBuild);
+ mCacheDir = PackageManagerServiceUtils.preparePackageParserCache(
+ mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
- // Set flag to monitor and not change apk file paths when
- // scanning install directories.
- int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
-
- if (mIsUpgrade || mFirstBoot) {
- scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
- }
-
- final int systemParseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
- final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
-
- PackageParser2 packageParser = injector.getScanningCachingPackageParser();
-
- ExecutorService executorService = ParallelPackageParser.makeExecutorService();
- // Prepare apex package info before scanning APKs, these information are needed when
- // scanning apk in apex.
- mApexManager.scanApexPackagesTraced(packageParser, executorService);
-
- mInitAndSystemPackageHelper.scanSystemDirs(mDirsToScanAsSystem, mIsUpgrade,
- packageParser, executorService, mPlatformPackage, mIsPreNMR1Upgrade,
- systemParseFlags, systemScanFlags);
- // Parse overlay configuration files to set default enable state, mutability, and
- // priority of system overlays.
- mOverlayConfig = OverlayConfig.initializeSystemInstance(
- consumer -> mPmInternal.forEachPackage(
- pkg -> consumer.accept(pkg, pkg.isSystem())));
final int[] userIds = mUserManager.getUserIds();
- mInitAndSystemPackageHelper.cleanupSystemPackagesAndInstallStubs(mDirsToScanAsSystem,
- mIsUpgrade, packageParser, executorService, mOnlyCore, packageSettings,
- startTime, mAppInstallDir, mPlatformPackage, mIsPreNMR1Upgrade,
- scanFlags, systemParseFlags, systemScanFlags, userIds);
- packageParser.close();
+ mOverlayConfig = mInitAndSystemPackageHelper.setUpSystemPackages(packageSettings,
+ userIds, startTime);
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName();
@@ -2073,7 +1959,7 @@
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
- + ((SystemClock.uptimeMillis()-startTime)/1000f)
+ + ((SystemClock.uptimeMillis() - startTime) / 1000f)
+ " seconds");
// If the build fingerprint has changed since the last time we booted,
@@ -2276,80 +2162,6 @@
setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr());
}
- private @Nullable File preparePackageParserCache(boolean forEngBuild) {
- if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
- if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
- return null;
- }
-
- // Disable package parsing on eng builds to allow for faster incremental development.
- if (forEngBuild) {
- return null;
- }
-
- if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
- Slog.i(TAG, "Disabling package parser cache due to system property.");
- return null;
- }
- }
-
- // The base directory for the package parser cache lives under /data/system/.
- final File cacheBaseDir = Environment.getPackageCacheDirectory();
- if (!FileUtils.createDir(cacheBaseDir)) {
- return null;
- }
-
- // There are several items that need to be combined together to safely
- // identify cached items. In particular, changing the value of certain
- // feature flags should cause us to invalidate any caches.
- final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
- : SystemProperties.digestOf("ro.build.fingerprint");
-
- // Reconcile cache directories, keeping only what we'd actually use.
- for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
- if (Objects.equals(cacheName, cacheDir.getName())) {
- Slog.d(TAG, "Keeping known cache " + cacheDir.getName());
- } else {
- Slog.d(TAG, "Destroying unknown cache " + cacheDir.getName());
- FileUtils.deleteContentsAndDir(cacheDir);
- }
- }
-
- // Return the versioned package cache directory.
- File cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
-
- if (cacheDir == null) {
- // Something went wrong. Attempt to delete everything and return.
- Slog.wtf(TAG, "Cache directory cannot be created - wiping base dir " + cacheBaseDir);
- FileUtils.deleteContentsAndDir(cacheBaseDir);
- return null;
- }
-
- // The following is a workaround to aid development on non-numbered userdebug
- // builds or cases where "adb sync" is used on userdebug builds. If we detect that
- // the system partition is newer.
- //
- // NOTE: When no BUILD_NUMBER is set by the build system, it defaults to a build
- // that starts with "eng." to signify that this is an engineering build and not
- // destined for release.
- if (mIsUserDebugBuild && mIncrementalVersion.startsWith("eng.")) {
- Slog.w(TAG, "Wiping cache directory because the system partition changed.");
-
- // Heuristic: If the /system directory has been modified recently due to an "adb sync"
- // or a regular make, then blow away the cache. Note that mtimes are *NOT* reliable
- // in general and should not be used for production changes. In this specific case,
- // we know that they will work.
- File frameworkDir =
- new File(Environment.getRootDirectory(), "framework");
- if (cacheDir.lastModified() < frameworkDir.lastModified()) {
- FileUtils.deleteContents(cacheBaseDir);
- cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
- }
- }
-
- return cacheDir;
- }
-
@Override
public boolean isFirstBoot() {
// allow instant applications
@@ -2968,7 +2780,6 @@
filterCallingUid, userId);
}
-
@Override
public void deletePreloadsFileCache() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
@@ -4005,7 +3816,8 @@
public List<String> getAllPackages() {
// Allow iorapd to call this method.
if (Binder.getCallingUid() != Process.IORAPD_UID) {
- enforceSystemOrRootOrShell("getAllPackages is limited to privileged callers");
+ PackageManagerServiceUtils.enforceSystemOrRootOrShell(
+ "getAllPackages is limited to privileged callers");
}
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
@@ -4972,34 +4784,6 @@
}
/**
- * Enforces that only the system UID or root's UID can call a method exposed
- * via Binder.
- *
- * @param message used as message if SecurityException is thrown
- * @throws SecurityException if the caller is not system or root
- */
- private static void enforceSystemOrRoot(String message) {
- final int uid = Binder.getCallingUid();
- if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID) {
- throw new SecurityException(message);
- }
- }
-
- /**
- * Enforces that only the system UID or root's UID or shell's UID can call
- * a method exposed via Binder.
- *
- * @param message used as message if SecurityException is thrown
- * @throws SecurityException if the caller is not system or shell
- */
- private static void enforceSystemOrRootOrShell(String message) {
- final int uid = Binder.getCallingUid();
- if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID && uid != Process.SHELL_UID) {
- throw new SecurityException(message);
- }
- }
-
- /**
* Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
* or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
*
@@ -5034,7 +4818,7 @@
@Override
public void performFstrimIfNeeded() {
- enforceSystemOrRoot("Only the system can request fstrim");
+ PackageManagerServiceUtils.enforceSystemOrRoot("Only the system can request fstrim");
// Before everything else, see whether we need to fstrim.
try {
@@ -5056,7 +4840,7 @@
if (doTrim) {
final boolean dexOptDialogShown;
synchronized (mLock) {
- dexOptDialogShown = mDexOptDialogShown;
+ dexOptDialogShown = mDexOptHelper.isDexOptDialogShown();
}
if (!isFirstBoot() && dexOptDialogShown) {
try {
@@ -5078,208 +4862,7 @@
@Override
public void updatePackagesIfNeeded() {
- enforceSystemOrRoot("Only the system can request package update");
-
- // We need to re-extract after an OTA.
- boolean causeUpgrade = isDeviceUpgrading();
-
- // First boot or factory reset.
- // Note: we also handle devices that are upgrading to N right now as if it is their
- // first boot, as they do not have profile data.
- boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;
-
- if (!causeUpgrade && !causeFirstBoot) {
- return;
- }
-
- List<PackageSetting> pkgSettings;
- synchronized (mLock) {
- pkgSettings = PackageManagerServiceUtils.getPackagesForDexopt(
- mSettings.getPackagesLocked().values(), this);
- }
-
- List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
- for (int index = 0; index < pkgSettings.size(); index++) {
- pkgs.add(pkgSettings.get(index).getPkg());
- }
-
- final long startTime = System.nanoTime();
- final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
- causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT_AFTER_OTA,
- false /* bootComplete */);
-
- final int elapsedTimeSeconds =
- (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
-
- MetricsLogger.histogram(mContext, "opt_dialog_num_dexopted", stats[0]);
- MetricsLogger.histogram(mContext, "opt_dialog_num_skipped", stats[1]);
- MetricsLogger.histogram(mContext, "opt_dialog_num_failed", stats[2]);
- MetricsLogger.histogram(mContext, "opt_dialog_num_total", getOptimizablePackages().size());
- MetricsLogger.histogram(mContext, "opt_dialog_time_s", elapsedTimeSeconds);
- }
-
- /*
- * Return the prebuilt profile path given a package base code path.
- */
- private static String getPrebuildProfilePath(AndroidPackage pkg) {
- return pkg.getBaseApkPath() + ".prof";
- }
-
- /**
- * Performs dexopt on the set of packages in {@code packages} and returns an int array
- * containing statistics about the invocation. The array consists of three elements,
- * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped}
- * and {@code numberOfPackagesFailed}.
- */
- private int[] performDexOptUpgrade(List<AndroidPackage> pkgs, boolean showDialog,
- final int compilationReason, boolean bootComplete) {
-
- int numberOfPackagesVisited = 0;
- int numberOfPackagesOptimized = 0;
- int numberOfPackagesSkipped = 0;
- int numberOfPackagesFailed = 0;
- final int numberOfPackagesToDexopt = pkgs.size();
-
- for (AndroidPackage pkg : pkgs) {
- numberOfPackagesVisited++;
-
- boolean useProfileForDexopt = false;
-
- if ((isFirstBoot() || isDeviceUpgrading()) && pkg.isSystem()) {
- // Copy over initial preopt profiles since we won't get any JIT samples for methods
- // that are already compiled.
- File profileFile = new File(getPrebuildProfilePath(pkg));
- // Copy profile if it exists.
- if (profileFile.exists()) {
- try {
- // We could also do this lazily before calling dexopt in
- // PackageDexOptimizer to prevent this happening on first boot. The issue
- // is that we don't have a good way to say "do this only once".
- if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.getUid(), pkg.getPackageName(),
- ArtManager.getProfileName(null))) {
- Log.e(TAG, "Installer failed to copy system profile!");
- } else {
- // Disabled as this causes speed-profile compilation during first boot
- // even if things are already compiled.
- // useProfileForDexopt = true;
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ",
- e);
- }
- } else {
- PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(
- pkg.getPackageName());
- // Handle compressed APKs in this path. Only do this for stubs with profiles to
- // minimize the number off apps being speed-profile compiled during first boot.
- // The other paths will not change the filter.
- if (disabledPs != null && disabledPs.getPkg().isStub()) {
- // The package is the stub one, remove the stub suffix to get the normal
- // package and APK names.
- String systemProfilePath = getPrebuildProfilePath(disabledPs.getPkg())
- .replace(STUB_SUFFIX, "");
- profileFile = new File(systemProfilePath);
- // If we have a profile for a compressed APK, copy it to the reference
- // location.
- // Note that copying the profile here will cause it to override the
- // reference profile every OTA even though the existing reference profile
- // may have more data. We can't copy during decompression since the
- // directories are not set up at that point.
- if (profileFile.exists()) {
- try {
- // We could also do this lazily before calling dexopt in
- // PackageDexOptimizer to prevent this happening on first boot. The
- // issue is that we don't have a good way to say "do this only
- // once".
- if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.getUid(), pkg.getPackageName(),
- ArtManager.getProfileName(null))) {
- Log.e(TAG, "Failed to copy system profile for stub package!");
- } else {
- useProfileForDexopt = true;
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to copy profile " +
- profileFile.getAbsolutePath() + " ", e);
- }
- }
- }
- }
- }
-
- if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName());
- }
- numberOfPackagesSkipped++;
- continue;
- }
-
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " +
- numberOfPackagesToDexopt + ": " + pkg.getPackageName());
- }
-
- if (showDialog) {
- try {
- ActivityManager.getService().showBootMessage(
- mContext.getResources().getString(R.string.android_upgrading_apk,
- numberOfPackagesVisited, numberOfPackagesToDexopt), true);
- } catch (RemoteException e) {
- }
- synchronized (mLock) {
- mDexOptDialogShown = true;
- }
- }
-
- int pkgCompilationReason = compilationReason;
- if (useProfileForDexopt) {
- // Use background dexopt mode to try and use the profile. Note that this does not
- // guarantee usage of the profile.
- pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
- }
-
- if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
- mArtManagerService.compileLayouts(pkg);
- }
-
- // checkProfiles is false to avoid merging profiles during boot which
- // might interfere with background compilation (b/28612421).
- // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
- // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
- // trade-off worth doing to save boot time work.
- int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
- if (compilationReason == REASON_FIRST_BOOT) {
- // TODO: This doesn't cover the upgrade case, we should check for this too.
- dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
- }
- int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
- pkg.getPackageName(),
- pkgCompilationReason,
- dexoptFlags));
-
- switch (primaryDexOptStaus) {
- case PackageDexOptimizer.DEX_OPT_PERFORMED:
- numberOfPackagesOptimized++;
- break;
- case PackageDexOptimizer.DEX_OPT_SKIPPED:
- numberOfPackagesSkipped++;
- break;
- case PackageDexOptimizer.DEX_OPT_CANCELLED:
- // ignore this case
- break;
- case PackageDexOptimizer.DEX_OPT_FAILED:
- numberOfPackagesFailed++;
- break;
- default:
- Log.e(TAG, "Unexpected dexopt return code " + primaryDexOptStaus);
- break;
- }
- }
-
- return new int[] { numberOfPackagesOptimized, numberOfPackagesSkipped,
- numberOfPackagesFailed };
+ mDexOptHelper.performPackageDexOptUpgradeIfNeeded();
}
@Override
@@ -5373,13 +4956,8 @@
public boolean performDexOptMode(String packageName,
boolean checkProfiles, String targetCompilerFilter, boolean force,
boolean bootComplete, String splitName) {
- enforceSystemOrRootOrShell("performDexOptMode");
-
- int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
- (force ? DexoptOptions.DEXOPT_FORCE : 0) |
- (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
- return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE,
- targetCompilerFilter, splitName, flags));
+ return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter,
+ force, bootComplete, splitName);
}
/**
@@ -5392,147 +4970,7 @@
@Override
public boolean performDexOptSecondary(String packageName, String compilerFilter,
boolean force) {
- int flags = DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX |
- DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES |
- DexoptOptions.DEXOPT_BOOT_COMPLETE |
- (force ? DexoptOptions.DEXOPT_FORCE : 0);
- return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags));
- }
-
- /*package*/ boolean performDexOpt(DexoptOptions options) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return false;
- } else if (isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) {
- return false;
- }
-
- if (options.isDexoptOnlySecondaryDex()) {
- return mDexManager.dexoptSecondaryDex(options);
- } else {
- int dexoptStatus = performDexOptWithStatus(options);
- return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
- }
- }
-
- /*package*/ void controlDexOptBlocking(boolean block) {
- mPackageDexOptimizer.controlDexOptBlocking(block);
- }
-
- /**
- * Perform dexopt on the given package and return one of following result:
- * {@link PackageDexOptimizer#DEX_OPT_SKIPPED}
- * {@link PackageDexOptimizer#DEX_OPT_PERFORMED}
- * {@link PackageDexOptimizer#DEX_OPT_CANCELLED}
- * {@link PackageDexOptimizer#DEX_OPT_FAILED}
- */
- @PackageDexOptimizer.DexOptResult
- /* package */ int performDexOptWithStatus(DexoptOptions options) {
- return performDexOptTraced(options);
- }
-
- private int performDexOptTraced(DexoptOptions options) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- try {
- return performDexOptInternal(options);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- // Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
- // if the package can now be considered up to date for the given filter.
- private int performDexOptInternal(DexoptOptions options) {
- AndroidPackage p;
- PackageSetting pkgSetting;
- synchronized (mLock) {
- p = mPackages.get(options.getPackageName());
- pkgSetting = mSettings.getPackageLPr(options.getPackageName());
- if (p == null || pkgSetting == null) {
- // Package could not be found. Report failure.
- return PackageDexOptimizer.DEX_OPT_FAILED;
- }
- mPackageUsage.maybeWriteAsync(mSettings.getPackagesLocked());
- mCompilerStats.maybeWriteAsync();
- }
- final long callingId = Binder.clearCallingIdentity();
- try {
- synchronized (mInstallLock) {
- return performDexOptInternalWithDependenciesLI(p, pkgSetting, options);
- }
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- }
-
- public ArraySet<String> getOptimizablePackages() {
- ArraySet<String> pkgs = new ArraySet<>();
- synchronized (mLock) {
- for (AndroidPackage p : mPackages.values()) {
- if (PackageDexOptimizer.canOptimizePackage(p)) {
- pkgs.add(p.getPackageName());
- }
- }
- }
- if (AppHibernationService.isAppHibernationEnabled()) {
- AppHibernationManagerInternal appHibernationManager =
- mInjector.getLocalService(AppHibernationManagerInternal.class);
- pkgs.removeIf(pkgName -> appHibernationManager.isHibernatingGlobally(pkgName));
- }
- return pkgs;
- }
-
- private int performDexOptInternalWithDependenciesLI(AndroidPackage p,
- @NonNull PackageSetting pkgSetting, DexoptOptions options) {
- // System server gets a special path.
- if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) {
- return mDexManager.dexoptSystemServer(options);
- }
-
- // Select the dex optimizer based on the force parameter.
- // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
- // allocate an object here.
- PackageDexOptimizer pdo = options.isForce()
- ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer)
- : mPackageDexOptimizer;
-
- // Dexopt all dependencies first. Note: we ignore the return value and march on
- // on errors.
- // Note that we are going to call performDexOpt on those libraries as many times as
- // they are referenced in packages. When we do a batch of performDexOpt (for example
- // at boot, or background job), the passed 'targetCompilerFilter' stays the same,
- // and the first package that uses the library will dexopt it. The
- // others will see that the compiled code for the library is up to date.
- Collection<SharedLibraryInfo> deps = findSharedLibraries(pkgSetting);
- final String[] instructionSets = getAppDexInstructionSets(
- AndroidPackageUtils.getPrimaryCpuAbi(p, pkgSetting),
- AndroidPackageUtils.getSecondaryCpuAbi(p, pkgSetting));
- if (!deps.isEmpty()) {
- DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
- options.getCompilationReason(), options.getCompilerFilter(),
- options.getSplitName(),
- options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
- for (SharedLibraryInfo info : deps) {
- AndroidPackage depPackage = null;
- PackageSetting depPackageSetting = null;
- synchronized (mLock) {
- depPackage = mPackages.get(info.getPackageName());
- depPackageSetting = mSettings.getPackageLPr(info.getPackageName());
- }
- if (depPackage != null && depPackageSetting != null) {
- // TODO: Analyze and investigate if we (should) profile libraries.
- pdo.performDexOpt(depPackage, depPackageSetting, instructionSets,
- getOrCreateCompilerPackageStats(depPackage),
- mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()),
- libraryOptions);
- } else {
- // TODO(ngeoffray): Support dexopting system shared libraries.
- }
- }
- }
-
- return pdo.performDexOpt(p, pkgSetting, instructionSets,
- getOrCreateCompilerPackageStats(p),
- mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options);
+ return mDexOptHelper.performDexOptSecondary(packageName, compilerFilter, force);
}
/**
@@ -5554,35 +4992,8 @@
return mDexManager;
}
- private static List<SharedLibraryInfo> findSharedLibraries(PackageSetting pkgSetting) {
- if (!pkgSetting.getPkgState().getUsesLibraryInfos().isEmpty()) {
- ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
- Set<String> collectedNames = new HashSet<>();
- for (SharedLibraryInfo info : pkgSetting.getPkgState().getUsesLibraryInfos()) {
- findSharedLibrariesRecursive(info, retValue, collectedNames);
- }
- return retValue;
- } else {
- return Collections.emptyList();
- }
- }
-
- private static void findSharedLibrariesRecursive(SharedLibraryInfo info,
- ArrayList<SharedLibraryInfo> collected, Set<String> collectedNames) {
- if (!collectedNames.contains(info.getName())) {
- collectedNames.add(info.getName());
- collected.add(info);
-
- if (info.getDependencies() != null) {
- for (SharedLibraryInfo dep : info.getDependencies()) {
- findSharedLibrariesRecursive(dep, collected, collectedNames);
- }
- }
- }
- }
-
List<PackageSetting> findSharedNonSystemLibraries(PackageSetting pkgSetting) {
- List<SharedLibraryInfo> deps = findSharedLibraries(pkgSetting);
+ List<SharedLibraryInfo> deps = SharedLibraryHelper.findSharedLibraries(pkgSetting);
if (!deps.isEmpty()) {
List<PackageSetting> retValue = new ArrayList<>();
synchronized (mLock) {
@@ -5686,33 +5097,7 @@
@Override
public void forceDexOpt(String packageName) {
- enforceSystemOrRoot("forceDexOpt");
-
- AndroidPackage pkg;
- PackageSetting pkgSetting;
- synchronized (mLock) {
- pkg = mPackages.get(packageName);
- pkgSetting = mSettings.getPackageLPr(packageName);
- if (pkg == null || pkgSetting == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- }
-
- synchronized (mInstallLock) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-
- // Whoever is calling forceDexOpt wants a compiled package.
- // Don't use profiles since that may cause compilation to be skipped.
- final int res = performDexOptInternalWithDependenciesLI(pkg, pkgSetting,
- new DexoptOptions(packageName,
- getDefaultCompilerFilter(),
- DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE));
-
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
- throw new IllegalStateException("Failed to dexopt: " + res);
- }
- }
+ mDexOptHelper.forceDexOpt(packageName);
}
int[] resolveUserIds(int userId) {
@@ -6971,7 +6356,8 @@
@Override
public void finishPackageInstall(int token, boolean didLaunch) {
- enforceSystemOrRoot("Only the system is allowed to finish installs");
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system is allowed to finish installs");
if (DEBUG_INSTALL) {
Slog.v(TAG, "BM finishing package install for " + token);
@@ -7367,18 +6753,6 @@
return mDevicePolicyManager;
}
- private static @Nullable ScanPartition resolveApexToScanPartition(
- ApexManager.ActiveApexInfo apexInfo) {
- for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
- ScanPartition sp = SYSTEM_PARTITIONS.get(i);
- if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath())) {
- return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
- }
- }
- return null;
- }
-
@Override
public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall,
int userId) {
@@ -7414,7 +6788,8 @@
@Override
public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) {
- enforceSystemOrRoot("setRequiredForSystemUser can only be run by the system or root");
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "setRequiredForSystemUser can only be run by the system or root");
synchronized (mLock) {
PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
@@ -7433,7 +6808,8 @@
@Override
public void clearApplicationProfileData(String packageName) {
- enforceSystemOrRoot("Only the system can clear all profile data");
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system can clear all profile data");
final AndroidPackage pkg;
synchronized (mLock) {
@@ -8431,8 +7807,7 @@
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
- if (!mInitAndSystemPackageHelper.enableCompressedPackage(deletedPkg, pkgSetting,
- mDefParseFlags, mDirsToScanAsSystem)) {
+ if (!mInitAndSystemPackageHelper.enableCompressedPackage(deletedPkg, pkgSetting)) {
Slog.w(TAG, "Failed setApplicationEnabledSetting: failed to enable "
+ "commpressed package " + setting.getPackageName());
updateAllowed[i] = false;
@@ -8888,7 +8263,8 @@
@Override
public void enterSafeMode() {
- enforceSystemOrRoot("Only the system can request entering safe mode");
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system can request entering safe mode");
if (!mSystemReady) {
mSafeMode = true;
@@ -8897,7 +8273,8 @@
@Override
public void systemReady() {
- enforceSystemOrRoot("Only the system can claim the system is ready");
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system can claim the system is ready");
final ContentResolver resolver = mContext.getContentResolver();
if (mReleaseOnSystemReady != null) {
@@ -9056,6 +8433,9 @@
mBackgroundDexOptService.systemReady();
}
+ /**
+ * Used by SystemServer
+ */
public void waitForAppDataPrepared() {
if (mPrepareAppDataFuture == null) {
return;
@@ -9487,200 +8867,6 @@
}
}
- private final class PackageChangeObserverDeathRecipient implements IBinder.DeathRecipient {
- private final IPackageChangeObserver mObserver;
-
- PackageChangeObserverDeathRecipient(IPackageChangeObserver observer) {
- mObserver = observer;
- }
-
- @Override
- public void binderDied() {
- synchronized (mPackageChangeObservers) {
- mPackageChangeObservers.remove(mObserver);
- Log.d(TAG, "Size of mPackageChangeObservers after removing dead observer is "
- + mPackageChangeObservers.size());
- }
- }
- }
-
- private class PackageManagerNative extends IPackageManagerNative.Stub {
- @Override
- public void registerPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
- synchronized (mPackageChangeObservers) {
- try {
- observer.asBinder().linkToDeath(
- new PackageChangeObserverDeathRecipient(observer), 0);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage());
- }
- mPackageChangeObservers.add(observer);
- Log.d(TAG, "Size of mPackageChangeObservers after registry is "
- + mPackageChangeObservers.size());
- }
- }
-
- @Override
- public void unregisterPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
- synchronized (mPackageChangeObservers) {
- mPackageChangeObservers.remove(observer);
- Log.d(TAG, "Size of mPackageChangeObservers after unregistry is "
- + mPackageChangeObservers.size());
- }
- }
-
- @Override
- public String[] getAllPackages() {
- return PackageManagerService.this.getAllPackages().toArray(new String[0]);
- }
-
- @Override
- public String[] getNamesForUids(int[] uids) throws RemoteException {
- String[] names = null;
- String[] results = null;
- try {
- if (uids == null || uids.length == 0) {
- return null;
- }
- names = PackageManagerService.this.getNamesForUids(uids);
- results = (names != null) ? names : new String[uids.length];
- // massage results so they can be parsed by the native binder
- for (int i = results.length - 1; i >= 0; --i) {
- if (results[i] == null) {
- results[i] = "";
- }
- }
- return results;
- } catch (Throwable t) {
- // STOPSHIP(186558987): revert addition of try/catch/log
- Slog.e(TAG, "uids: " + Arrays.toString(uids));
- Slog.e(TAG, "names: " + Arrays.toString(names));
- Slog.e(TAG, "results: " + Arrays.toString(results));
- Slog.e(TAG, "throwing exception", t);
- throw t;
- }
- }
-
- // NB: this differentiates between preloads and sideloads
- @Override
- public String getInstallerForPackage(String packageName) throws RemoteException {
- final String installerName = getInstallerPackageName(packageName);
- if (!TextUtils.isEmpty(installerName)) {
- return installerName;
- }
- // differentiate between preload and sideload
- int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- ApplicationInfo appInfo = getApplicationInfo(packageName,
- /*flags*/ 0,
- /*userId*/ callingUser);
- if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- return "preload";
- }
- return "";
- }
-
- @Override
- public long getVersionCodeForPackage(String packageName) throws RemoteException {
- try {
- int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- PackageInfo pInfo = getPackageInfo(packageName, 0, callingUser);
- if (pInfo != null) {
- return pInfo.getLongVersionCode();
- }
- } catch (Exception e) {
- }
- return 0;
- }
-
- @Override
- public int getTargetSdkVersionForPackage(String packageName) throws RemoteException {
- int targetSdk = getTargetSdkVersion(packageName);
- if (targetSdk != -1) {
- return targetSdk;
- }
-
- throw new RemoteException("Couldn't get targetSdkVersion for package " + packageName);
- }
-
- @Override
- public boolean isPackageDebuggable(String packageName) throws RemoteException {
- int callingUser = UserHandle.getCallingUserId();
- ApplicationInfo appInfo = getApplicationInfo(packageName, 0, callingUser);
- if (appInfo != null) {
- return (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE));
- }
-
- throw new RemoteException("Couldn't get debug flag for package " + packageName);
- }
-
- @Override
- public boolean[] isAudioPlaybackCaptureAllowed(String[] packageNames)
- throws RemoteException {
- int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- boolean[] results = new boolean[packageNames.length];
- for (int i = results.length - 1; i >= 0; --i) {
- ApplicationInfo appInfo = getApplicationInfo(packageNames[i], 0, callingUser);
- results[i] = appInfo != null && appInfo.isAudioPlaybackCaptureAllowed();
- }
- return results;
- }
-
- @Override
- public int getLocationFlags(String packageName) throws RemoteException {
- int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- ApplicationInfo appInfo = getApplicationInfo(packageName,
- /*flags*/ 0,
- /*userId*/ callingUser);
- if (appInfo == null) {
- throw new RemoteException(
- "Couldn't get ApplicationInfo for package " + packageName);
- }
- return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0)
- | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
- | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0));
- }
-
- @Override
- public String getModuleMetadataPackageName() throws RemoteException {
- return PackageManagerService.this.mModuleInfoProvider.getPackageName();
- }
-
- @Override
- public boolean hasSha256SigningCertificate(String packageName, byte[] certificate)
- throws RemoteException {
- return PackageManagerService.this.hasSigningCertificate(
- packageName, certificate, CERT_INPUT_SHA256);
- }
-
- @Override
- public boolean hasSystemFeature(String featureName, int version) {
- return PackageManagerService.this.hasSystemFeature(featureName, version);
- }
-
- @Override
- public void registerStagedApexObserver(IStagedApexObserver observer) {
- mInstallerService.getStagingManager().registerStagedApexObserver(observer);
- }
-
- @Override
- public void unregisterStagedApexObserver(IStagedApexObserver observer) {
- mInstallerService.getStagingManager().unregisterStagedApexObserver(observer);
- }
-
- @Override
- public String[] getStagedApexModuleNames() {
- return mInstallerService.getStagingManager()
- .getStagedApexModuleNames().toArray(new String[0]);
- }
-
- @Override
- @Nullable
- public StagedApexInfo getStagedApexInfo(String moduleName) {
- return mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
- }
-
- }
-
private AndroidPackage getPackage(String packageName) {
return mComputer.getPackage(packageName);
}
@@ -10174,17 +9360,6 @@
SparseArray<String> profileOwnerPackages) {
mProtectedPackages.setDeviceAndProfileOwnerPackages(
deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
-
- final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>();
- if (deviceOwnerPackage != null) {
- usersWithPoOrDo.add(deviceOwnerUserId);
- }
- final int sz = profileOwnerPackages.size();
- for (int i = 0; i < sz; i++) {
- if (profileOwnerPackages.valueAt(i) != null) {
- usersWithPoOrDo.add(profileOwnerPackages.keyAt(i));
- }
- }
}
@Override
@@ -11437,7 +10612,7 @@
* Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's
* writeLegacyPermissionsTEMP() beforehand.
*
- * TODO(zhanghai): This should be removed once we finish migration of permission storage.
+ * TODO(b/182523293): This should be removed once we finish migration of permission storage.
*/
void writeSettingsLPrTEMP() {
mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
@@ -11678,10 +10853,6 @@
return mCacheDir;
}
- List<ScanPartition> getDirsToScanAsSystem() {
- return mDirsToScanAsSystem;
- }
-
PackageProperty getPackageProperty() {
return mPackageProperty;
}
@@ -11795,4 +10966,126 @@
ResolveInfo getInstantAppInstallerInfo() {
return mInstantAppInstallerInfo;
}
+
+ PackageUsage getPackageUsage() {
+ return mPackageUsage;
+ }
+
+ String getModuleMetadataPackageName() {
+ return mModuleInfoProvider.getPackageName();
+ }
+
+ File getAppInstallDir() {
+ return mAppInstallDir;
+ }
+
+ boolean isExpectingBetter(String packageName) {
+ return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
+ }
+
+ int getDefParseFlags() {
+ return mDefParseFlags;
+ }
+
+ void setUpCustomResolverActivity(AndroidPackage pkg, PackageSetting pkgSetting) {
+ synchronized (mLock) {
+ mResolverReplaced = true;
+
+ // The instance created in PackageManagerService is special cased to be non-user
+ // specific, so initialize all the needed fields here.
+ ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0,
+ PackageUserState.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting);
+
+ // Set up information for custom user intent resolution activity.
+ mResolveActivity.applicationInfo = appInfo;
+ mResolveActivity.name = mCustomResolverComponentName.getClassName();
+ mResolveActivity.packageName = pkg.getPackageName();
+ mResolveActivity.processName = pkg.getProcessName();
+ mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
+ | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+ mResolveActivity.theme = 0;
+ mResolveActivity.exported = true;
+ mResolveActivity.enabled = true;
+ mResolveInfo.activityInfo = mResolveActivity;
+ mResolveInfo.priority = 0;
+ mResolveInfo.preferredOrder = 0;
+ mResolveInfo.match = 0;
+ mResolveComponentName = mCustomResolverComponentName;
+ PackageManagerService.onChanged();
+ Slog.i(TAG, "Replacing default ResolverActivity with custom activity: "
+ + mResolveComponentName);
+ }
+ }
+
+ void setPlatformPackage(AndroidPackage pkg, PackageSetting pkgSetting) {
+ synchronized (mLock) {
+ // Set up information for our fall-back user intent resolution activity.
+ mPlatformPackage = pkg;
+
+ // The instance stored in PackageManagerService is special cased to be non-user
+ // specific, so initialize all the needed fields here.
+ mAndroidApplication = PackageInfoUtils.generateApplicationInfo(pkg, 0,
+ PackageUserState.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting);
+
+ if (!mResolverReplaced) {
+ mResolveActivity.applicationInfo = mAndroidApplication;
+ mResolveActivity.name = ResolverActivity.class.getName();
+ mResolveActivity.packageName = mAndroidApplication.packageName;
+ mResolveActivity.processName = "system:ui";
+ mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
+ mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+ mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
+ mResolveActivity.exported = true;
+ mResolveActivity.enabled = true;
+ mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+ mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_ORIENTATION
+ | ActivityInfo.CONFIG_KEYBOARD
+ | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+ mResolveInfo.activityInfo = mResolveActivity;
+ mResolveInfo.priority = 0;
+ mResolveInfo.preferredOrder = 0;
+ mResolveInfo.match = 0;
+ mResolveComponentName = new ComponentName(
+ mAndroidApplication.packageName, mResolveActivity.name);
+ }
+ PackageManagerService.onChanged();
+ }
+ }
+
+ ResolveInfo getResolveInfo() {
+ return mResolveInfo;
+ }
+
+ ApplicationInfo getCoreAndroidApplication() {
+ return mAndroidApplication;
+ }
+
+ boolean isSystemReady() {
+ return mSystemReady;
+ }
+
+ AndroidPackage getPlatformPackage() {
+ return mPlatformPackage;
+ }
+
+ boolean isPreNUpgrade() {
+ return mIsPreNUpgrade;
+ }
+
+ boolean isPreNMR1Upgrade() {
+ return mIsPreNMR1Upgrade;
+ }
+
+ InitAndSystemPackageHelper getInitAndSystemPackageHelper() {
+ return mInitAndSystemPackageHelper;
+ }
+
+ boolean isOverlayMutable(String packageName) {
+ return mOverlayConfig.isMutable(packageName);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index c1c32dd..9327c5f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -102,4 +102,12 @@
public int sdkInt = Build.VERSION.SDK_INT;
public BackgroundDexOptService backgroundDexOptService;
public final String incrementalVersion = Build.VERSION.INCREMENTAL;
+ public BroadcastHelper broadcastHelper;
+ public AppDataHelper appDataHelper;
+ public RemovePackageHelper removePackageHelper;
+ public InitAndSystemPackageHelper initAndSystemPackageHelper;
+ public DeletePackageHelper deletePackageHelper;
+ public PreferredActivityHelper preferredActivityHelper;
+ public ResolveIntentHelper resolveIntentHelper;
+ public DexOptHelper dexOptHelper;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 9f586bc..e124e04 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -23,7 +23,6 @@
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_DEXOPT;
import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
import static com.android.server.pm.PackageManagerService.DEBUG_PREFERRED;
import static com.android.server.pm.PackageManagerService.RANDOM_DIR_PREFIX;
@@ -33,7 +32,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.AppGlobals;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.Context;
@@ -45,7 +43,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -53,14 +50,13 @@
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Binder;
import android.os.Build;
import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
-import android.os.RemoteException;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
import android.os.incremental.V4Signature;
import android.os.incremental.V4Signature.HashingInfo;
@@ -86,11 +82,9 @@
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
-import com.android.server.utils.WatchedLongSparseArray;
import dalvik.system.VMRuntime;
@@ -112,14 +106,10 @@
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
+import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
@@ -130,7 +120,6 @@
* {@hide}
*/
public class PackageManagerServiceUtils {
- private static final long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000;
private static final long MAX_CRITICAL_INFO_DUMP_SIZE = 3 * 1000 * 1000; // 3MB
public final static Predicate<PackageSetting> REMOVE_IF_NULL_PKG =
@@ -150,151 +139,18 @@
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188;
- private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
- List<ResolveInfo> ris = null;
- try {
- ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId)
- .getList();
- } catch (RemoteException e) {
- }
- ArraySet<String> pkgNames = new ArraySet<String>();
- if (ris != null) {
- for (ResolveInfo ri : ris) {
- pkgNames.add(ri.activityInfo.packageName);
- }
- }
- return pkgNames;
- }
+ /**
+ * The initial enabled state of the cache before other checks are done.
+ */
+ private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
- // Sort a list of apps by their last usage, most recently used apps first. The order of
- // packages without usage data is undefined (but they will be sorted after the packages
- // that do have usage data).
- public static void sortPackagesByUsageDate(List<PackageSetting> pkgSettings,
- PackageManagerService packageManagerService) {
- if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
- return;
- }
-
- Collections.sort(pkgSettings, (pkgSetting1, pkgSetting2) ->
- Long.compare(
- pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills(),
- pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills())
- );
- }
-
- // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the
- // package will be removed from {@code packages} and added to {@code result} with its
- // dependencies. If usage data is available, the positive packages will be sorted by usage
- // data (with {@code sortTemp} as temporary storage).
- private static void applyPackageFilter(
- Predicate<PackageSetting> filter,
- Collection<PackageSetting> result,
- Collection<PackageSetting> packages,
- @NonNull List<PackageSetting> sortTemp,
- PackageManagerService packageManagerService) {
- for (PackageSetting pkgSetting : packages) {
- if (filter.test(pkgSetting)) {
- sortTemp.add(pkgSetting);
- }
- }
-
- sortPackagesByUsageDate(sortTemp, packageManagerService);
- packages.removeAll(sortTemp);
-
- for (PackageSetting pkgSetting : sortTemp) {
- result.add(pkgSetting);
-
- List<PackageSetting> deps =
- packageManagerService.findSharedNonSystemLibraries(pkgSetting);
- if (!deps.isEmpty()) {
- deps.removeAll(result);
- result.addAll(deps);
- packages.removeAll(deps);
- }
- }
-
- sortTemp.clear();
- }
-
- // Sort apps by importance for dexopt ordering. Important apps are given
- // more priority in case the device runs out of space.
- public static List<PackageSetting> getPackagesForDexopt(
- Collection<PackageSetting> packages,
- PackageManagerService packageManagerService) {
- return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
- }
-
- public static List<PackageSetting> getPackagesForDexopt(
- Collection<PackageSetting> pkgSettings,
- PackageManagerService packageManagerService,
- boolean debug) {
- List<PackageSetting> result = new LinkedList<>();
- ArrayList<PackageSetting> remainingPkgSettings = new ArrayList<>(pkgSettings);
-
- // First, remove all settings without available packages
- remainingPkgSettings.removeIf(REMOVE_IF_NULL_PKG);
-
- ArrayList<PackageSetting> sortTemp = new ArrayList<>(remainingPkgSettings.size());
-
- // Give priority to core apps.
- applyPackageFilter(pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
- remainingPkgSettings, sortTemp, packageManagerService);
-
- // Give priority to system apps that listen for pre boot complete.
- Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
- final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
- applyPackageFilter(pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
- remainingPkgSettings, sortTemp, packageManagerService);
-
- // Give priority to apps used by other apps.
- DexManager dexManager = packageManagerService.getDexManager();
- applyPackageFilter(pkgSetting ->
- dexManager.getPackageUseInfoOrDefault(pkgSetting.getPackageName())
- .isAnyCodePathUsedByOtherApps(),
- result, remainingPkgSettings, sortTemp, packageManagerService);
-
- // Filter out packages that aren't recently used, add all remaining apps.
- // TODO: add a property to control this?
- Predicate<PackageSetting> remainingPredicate;
- if (!remainingPkgSettings.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
- if (debug) {
- Log.i(TAG, "Looking at historical package use");
- }
- // Get the package that was used last.
- PackageSetting lastUsed = Collections.max(remainingPkgSettings,
- (pkgSetting1, pkgSetting2) -> Long.compare(
- pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills(),
- pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills()));
- if (debug) {
- Log.i(TAG, "Taking package " + lastUsed.getPackageName()
- + " as reference in time use");
- }
- long estimatedPreviousSystemUseTime = lastUsed.getPkgState()
- .getLatestForegroundPackageUseTimeInMills();
- // Be defensive if for some reason package usage has bogus data.
- if (estimatedPreviousSystemUseTime != 0) {
- final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
- remainingPredicate = pkgSetting -> pkgSetting.getPkgState()
- .getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
- } else {
- // No meaningful historical info. Take all.
- remainingPredicate = pkgSetting -> true;
- }
- sortPackagesByUsageDate(remainingPkgSettings, packageManagerService);
- } else {
- // No historical info. Take all.
- remainingPredicate = pkgSetting -> true;
- }
- applyPackageFilter(remainingPredicate, result, remainingPkgSettings, sortTemp,
- packageManagerService);
-
- if (debug) {
- Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
- Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgSettings));
- }
-
- return result;
- }
+ /**
+ * Whether to skip all other checks and force the cache to be enabled.
+ *
+ * Setting this to true will cause the cache to be named "debug" to avoid eviction from
+ * build fingerprint changes.
+ */
+ private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false;
/**
* Checks if the package was inactive during since <code>thresholdTimeinMillis</code>.
@@ -343,17 +199,6 @@
}
}
- public static String packagesToString(List<PackageSetting> pkgSettings) {
- StringBuilder sb = new StringBuilder();
- for (int index = 0; index < pkgSettings.size(); index++) {
- if (sb.length() > 0) {
- sb.append(", ");
- }
- sb.append(pkgSettings.get(index).getPackageName());
- }
- return sb.toString();
- }
-
/**
* Verifies that the given string {@code isa} is a valid supported isa on
* the running device.
@@ -1277,4 +1122,107 @@
}
return StorageEnums.UNKNOWN;
}
+
+ /**
+ * Enforces that only the system UID or root's UID or shell's UID can call
+ * a method exposed via Binder.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or shell
+ */
+ public static void enforceSystemOrRootOrShell(String message) {
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID && uid != Process.SHELL_UID) {
+ throw new SecurityException(message);
+ }
+ }
+
+ /**
+ * Enforces that only the system UID or root's UID can call a method exposed
+ * via Binder.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ */
+ public static void enforceSystemOrRoot(String message) {
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID) {
+ throw new SecurityException(message);
+ }
+ }
+
+ public static @Nullable File preparePackageParserCache(boolean forEngBuild,
+ boolean isUserDebugBuild, String incrementalVersion) {
+ if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
+ if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
+ return null;
+ }
+
+ // Disable package parsing on eng builds to allow for faster incremental development.
+ if (forEngBuild) {
+ return null;
+ }
+
+ if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
+ Slog.i(TAG, "Disabling package parser cache due to system property.");
+ return null;
+ }
+ }
+
+ // The base directory for the package parser cache lives under /data/system/.
+ final File cacheBaseDir = Environment.getPackageCacheDirectory();
+ if (!FileUtils.createDir(cacheBaseDir)) {
+ return null;
+ }
+
+ // There are several items that need to be combined together to safely
+ // identify cached items. In particular, changing the value of certain
+ // feature flags should cause us to invalidate any caches.
+ final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
+ : SystemProperties.digestOf("ro.build.fingerprint");
+
+ // Reconcile cache directories, keeping only what we'd actually use.
+ for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
+ if (Objects.equals(cacheName, cacheDir.getName())) {
+ Slog.d(TAG, "Keeping known cache " + cacheDir.getName());
+ } else {
+ Slog.d(TAG, "Destroying unknown cache " + cacheDir.getName());
+ FileUtils.deleteContentsAndDir(cacheDir);
+ }
+ }
+
+ // Return the versioned package cache directory.
+ File cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
+
+ if (cacheDir == null) {
+ // Something went wrong. Attempt to delete everything and return.
+ Slog.wtf(TAG, "Cache directory cannot be created - wiping base dir " + cacheBaseDir);
+ FileUtils.deleteContentsAndDir(cacheBaseDir);
+ return null;
+ }
+
+ // The following is a workaround to aid development on non-numbered userdebug
+ // builds or cases where "adb sync" is used on userdebug builds. If we detect that
+ // the system partition is newer.
+ //
+ // NOTE: When no BUILD_NUMBER is set by the build system, it defaults to a build
+ // that starts with "eng." to signify that this is an engineering build and not
+ // destined for release.
+ if (isUserDebugBuild && incrementalVersion.startsWith("eng.")) {
+ Slog.w(TAG, "Wiping cache directory because the system partition changed.");
+
+ // Heuristic: If the /system directory has been modified recently due to an "adb sync"
+ // or a regular make, then blow away the cache. Note that mtimes are *NOT* reliable
+ // in general and should not be used for production changes. In this specific case,
+ // we know that they will work.
+ File frameworkDir =
+ new File(Environment.getRootDirectory(), "framework");
+ if (cacheDir.lastModified() < frameworkDir.lastModified()) {
+ FileUtils.deleteContents(cacheBaseDir);
+ cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
+ }
+ }
+
+ return cacheDir;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index 74e1050..a60d2c8 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -32,7 +32,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
-public final class PackageRemovedInfo {
+final class PackageRemovedInfo {
final PackageSender mPackageSender;
String mRemovedPackage;
String mInstallerPackageName;
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 8c05ba7..68e880b 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -135,7 +135,7 @@
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
}
- if (!mPm.mSystemReady) {
+ if (!mPm.isSystemReady()) {
// We might get called before system is ready because of package changes etc, but
// finding preferred activity depends on settings provider, so we ignore the update
// before that.
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index cead177..f5010e4 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -164,7 +164,7 @@
& PackageManagerInternal.RESOLVE_NON_RESOLVER_ONLY) != 0) {
return null;
}
- ri = new ResolveInfo(mPm.mResolveInfo);
+ ri = new ResolveInfo(mPm.getResolveInfo());
// if all resolve options are browsers, mark the resolver's info as if it were
// also a browser.
ri.handleAllWebDataURI = browserCount == n;
@@ -586,7 +586,7 @@
if (ri == null) {
continue;
}
- if (ri == mPm.mResolveInfo) {
+ if (ri == mPm.getResolveInfo()) {
// ACK! Must do something better with this.
}
ai = ri.activityInfo;
diff --git a/services/core/java/com/android/server/pm/ScanPackageHelper.java b/services/core/java/com/android/server/pm/ScanPackageHelper.java
index 616aec5..8018011 100644
--- a/services/core/java/com/android/server/pm/ScanPackageHelper.java
+++ b/services/core/java/com/android/server/pm/ScanPackageHelper.java
@@ -219,8 +219,7 @@
PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user,
- mPm.mPlatformPackage, mPm.mIsUpgrade, mPm.mIsPreNMR1Upgrade);
+ return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
}
// TODO(b/199937291): scanPackageNewLI() and scanPackageOnlyLI() should be merged.
@@ -259,7 +258,7 @@
} else {
isUpdatedSystemApp = disabledPkgSetting != null;
}
- applyPolicy(parsedPackage, scanFlags, mPm.mPlatformPackage, isUpdatedSystemApp);
+ applyPolicy(parsedPackage, scanFlags, mPm.getPlatformPackage(), isUpdatedSystemApp);
assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
SharedUserSetting sharedUserSetting = null;
@@ -275,8 +274,8 @@
}
}
}
- String platformPackageName = mPm.mPlatformPackage == null
- ? null : mPm.mPlatformPackage.getPackageName();
+ String platformPackageName = mPm.getPlatformPackage() == null
+ ? null : mPm.getPlatformPackage().getPackageName();
final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
pkgSetting == null ? null : pkgSetting.getPkg(), pkgSetting, disabledPkgSetting,
originalPkgSetting, realPkgName, parseFlags, scanFlags,
@@ -767,8 +766,7 @@
public AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags, long currentTime,
- @Nullable UserHandle user, AndroidPackage platformPackage, boolean isUpgrade,
- boolean isPreNMR1Upgrade) throws PackageManagerException {
+ @Nullable UserHandle user) throws PackageManagerException {
final boolean scanSystemPartition =
(parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
final String renamedPkgName;
@@ -776,8 +774,11 @@
final boolean isSystemPkgUpdated;
final boolean pkgAlreadyExists;
PackageSetting pkgSetting;
+ AndroidPackage platformPackage;
+ final boolean isUpgrade = mPm.isDeviceUpgrading();
synchronized (mPm.mLock) {
+ platformPackage = mPm.getPlatformPackage();
renamedPkgName = mPm.mSettings.getRenamedPackageLPr(
AndroidPackageUtils.getRealPackageOrNull(parsedPackage));
final String realPkgName = getRealPackageName(parsedPackage,
@@ -826,8 +827,8 @@
if (isSystemPkgUpdated) {
// we're updating the disabled package, so, scan it as the package setting
boolean isPlatformPackage = platformPackage != null
- && Objects.equals(platformPackage.getPackageName(),
- parsedPackage.getPackageName());
+ && platformPackage.getPackageName().equals(
+ parsedPackage.getPackageName());
final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
null, disabledPkgSetting /* pkgSetting */,
null /* disabledPkgSetting */, null /* originalPkgSetting */,
@@ -911,8 +912,7 @@
// TODO(b/136132412): skip for Incremental installation
final boolean skipVerify = scanSystemPartition
|| (forceCollect && canSkipForcedPackageVerification(parsedPackage));
- collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify,
- isPreNMR1Upgrade);
+ collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
// Reset profile if the application version is changed
maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
@@ -1075,11 +1075,10 @@
}
private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
- boolean forceCollect, boolean skipVerify, boolean mIsPreNMR1Upgrade)
- throws PackageManagerException {
+ boolean forceCollect, boolean skipVerify) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
// directory and not the APK file.
- final long lastModifiedTime = mIsPreNMR1Upgrade
+ final long lastModifiedTime = mPm.isPreNMR1Upgrade()
? new File(parsedPackage.getPath()).lastModified()
: getLastModifiedTime(parsedPackage);
final Settings.VersionInfo settingsVersionForPackage =
@@ -1250,7 +1249,7 @@
synchronized (mPm.mLock) {
// The special "android" package can only be defined once
if (pkg.getPackageName().equals("android")) {
- if (mPm.mAndroidApplication != null) {
+ if (mPm.getCoreAndroidApplication() != null) {
Slog.w(TAG, "*************************************************");
Slog.w(TAG, "Core android package being redefined. Skipping.");
Slog.w(TAG, " codePath=" + pkg.getPath());
@@ -1401,7 +1400,7 @@
// to the user-installed location. If we don't allow this change, any newer,
// user-installed version of the application will be ignored.
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
- if (mPm.mExpectingBetter.containsKey(pkg.getPackageName())) {
+ if (mPm.isExpectingBetter(pkg.getPackageName())) {
Slog.w(TAG, "Relax SCAN_REQUIRE_KNOWN requirement for package "
+ pkg.getPackageName());
} else {
@@ -1482,9 +1481,7 @@
if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
// This must be an update to a system overlay. Immutable overlays cannot be
// upgraded.
- Objects.requireNonNull(mPm.mOverlayConfig,
- "Parsing non-system dir before overlay configs are initialized");
- if (!mPm.mOverlayConfig.isMutable(pkg.getPackageName())) {
+ if (!mPm.isOverlayMutable(pkg.getPackageName())) {
throw new PackageManagerException("Overlay "
+ pkg.getPackageName()
+ " is static and cannot be upgraded.");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7126909..f89d9eb 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3002,17 +3002,6 @@
}
}
- // If the build is setup to drop runtime permissions
- // on update drop the files before loading them.
- if (PackageManagerService.CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE) {
- final VersionInfo internal = getInternalVersion();
- if (!Build.FINGERPRINT.equals(internal.fingerprint)) {
- for (UserInfo user : users) {
- mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(user.id);
- }
- }
- }
-
final int N = mPendingPackages.size();
for (int i = 0; i < N; i++) {
diff --git a/services/core/java/com/android/server/pm/SharedLibraryHelper.java b/services/core/java/com/android/server/pm/SharedLibraryHelper.java
index 55e90a5..2582316 100644
--- a/services/core/java/com/android/server/pm/SharedLibraryHelper.java
+++ b/services/core/java/com/android/server/pm/SharedLibraryHelper.java
@@ -41,8 +41,10 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
final class SharedLibraryHelper {
private static final boolean DEBUG_SHARED_LIBRARIES = false;
@@ -323,4 +325,32 @@
}
return versionedLib.get(version);
}
+
+ public static List<SharedLibraryInfo> findSharedLibraries(PackageSetting pkgSetting) {
+ if (!pkgSetting.getPkgState().getUsesLibraryInfos().isEmpty()) {
+ ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
+ Set<String> collectedNames = new HashSet<>();
+ for (SharedLibraryInfo info : pkgSetting.getPkgState().getUsesLibraryInfos()) {
+ findSharedLibrariesRecursive(info, retValue, collectedNames);
+ }
+ return retValue;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ private static void findSharedLibrariesRecursive(SharedLibraryInfo info,
+ ArrayList<SharedLibraryInfo> collected, Set<String> collectedNames) {
+ if (!collectedNames.contains(info.getName())) {
+ collectedNames.add(info.getName());
+ collected.add(info);
+
+ if (info.getDependencies() != null) {
+ for (SharedLibraryInfo dep : info.getDependencies()) {
+ findSharedLibrariesRecursive(dep, collected, collectedNames);
+ }
+ }
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index a82cb9e..b49c8da 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -132,7 +132,7 @@
final AppDataHelper appDataHelper = new AppDataHelper(mPm);
final ArrayList<PackageFreezer> freezers = new ArrayList<>();
final ArrayList<AndroidPackage> loaded = new ArrayList<>();
- final int parseFlags = mPm.mDefParseFlags | ParsingPackageUtils.PARSE_EXTERNAL_STORAGE;
+ final int parseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_EXTERNAL_STORAGE;
final Settings.VersionInfo ver;
final List<PackageSetting> packages;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index 72bc77e..3ee2348 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -105,7 +105,7 @@
rule.system().validateFinalState()
whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
- val optimizablePkgs = pm.optimizablePackages
+ val optimizablePkgs = DexOptHelper(pm).optimizablePackages
assertTrue(optimizablePkgs.contains(TEST_PACKAGE_NAME))
assertFalse(optimizablePkgs.contains(TEST_PACKAGE_2_NAME))