diff options
| author | 2023-01-11 08:38:26 +0000 | |
|---|---|---|
| committer | 2023-01-11 08:38:26 +0000 | |
| commit | b4c2c4f9f66e17400eba61319458c2da99a2812b (patch) | |
| tree | a5c7217d6d021883b2c01fde35fd9338de323209 | |
| parent | 4326b85ba0349a25b1c32e06288b872f255baeac (diff) | |
| parent | c22b83ab1af775cb94798f1ad4822702bc7aaa9b (diff) | |
Merge changes from topics "art-service-dynamic-code-logger", "art-service-shell-command"
* changes:
Forward some root-level PM shell commands to ART Service.
Integrate ART Service with DynamicCodeLogger.
Take DynamicCodeLogger out of DexManager.
11 files changed, 241 insertions, 114 deletions
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java index abaff4afeeea..d252d409732a 100644 --- a/services/core/java/com/android/server/pm/AppDataHelper.java +++ b/services/core/java/com/android/server/pm/AppDataHelper.java @@ -616,6 +616,7 @@ public class AppDataHelper { Slog.w(TAG, String.valueOf(e)); } mPm.getDexManager().notifyPackageDataDestroyed(pkg.getPackageName(), userId); + mPm.getDynamicCodeLogger().notifyPackageDataDestroyed(pkg.getPackageName(), userId); } } diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java index b4bcd5b3308c..cae7079c75e0 100644 --- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java +++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java @@ -27,13 +27,17 @@ import android.os.Process; import android.util.EventLog; import android.util.Log; +import com.android.server.LocalManagerRegistry; import com.android.server.LocalServices; +import com.android.server.art.DexUseManagerLocal; +import com.android.server.art.model.DexContainerFileUseInfo; import com.android.server.pm.dex.DynamicCodeLogger; import libcore.util.HexEncoding; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -137,6 +141,28 @@ public class DynamicCodeLoggingService extends JobService { return LocalServices.getService(PackageManagerInternal.class).getDynamicCodeLogger(); } + private static void syncDataFromArtService(DynamicCodeLogger dynamicCodeLogger) { + DexUseManagerLocal dexUseManagerLocal = DexOptHelper.getDexUseManagerLocal(); + if (dexUseManagerLocal == null) { + // ART Service is not enabled. + return; + } + PackageManagerLocal packageManagerLocal = + Objects.requireNonNull(LocalManagerRegistry.getManager(PackageManagerLocal.class)); + try (PackageManagerLocal.UnfilteredSnapshot snapshot = + packageManagerLocal.withUnfilteredSnapshot()) { + for (String owningPackageName : snapshot.getPackageStates().keySet()) { + for (DexContainerFileUseInfo info : + dexUseManagerLocal.getSecondaryDexContainerFileUseInfo(owningPackageName)) { + for (String loadingPackageName : info.getLoadingPackages()) { + dynamicCodeLogger.recordDex(info.getUserHandle().getIdentifier(), + info.getDexContainerFile(), owningPackageName, loadingPackageName); + } + } + } + } + } + private class IdleLoggingThread extends Thread { private final JobParameters mParams; @@ -152,6 +178,7 @@ public class DynamicCodeLoggingService extends JobService { } DynamicCodeLogger dynamicCodeLogger = getDynamicCodeLogger(); + syncDataFromArtService(dynamicCodeLogger); for (String packageName : dynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()) { if (mIdleLoggingStopRequested) { Log.w(TAG, "Stopping IdleLoggingJob run at scheduler request"); diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java index 04f5e56c4eb7..99fff720221e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java +++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java @@ -49,7 +49,6 @@ import android.util.SparseArray; import com.android.server.pm.Installer.LegacyDexoptDisabledException; import com.android.server.pm.dex.DexManager; -import com.android.server.pm.dex.DynamicCodeLogger; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; @@ -773,10 +772,4 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { public final void shutdown() { mService.shutdown(); } - - @Override - @Deprecated - public final DynamicCodeLogger getDynamicCodeLogger() { - return getDexManager().getDynamicCodeLogger(); - } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9a98e1e7d0e6..d7cecff2fcc9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -204,6 +204,7 @@ import com.android.server.pm.Settings.VersionInfo; 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.DynamicCodeLogger; import com.android.server.pm.dex.ViewCompiler; import com.android.server.pm.local.PackageManagerLocalImpl; import com.android.server.pm.parsing.PackageInfoUtils; @@ -793,6 +794,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package // is used by other apps). private final DexManager mDexManager; + private final DynamicCodeLogger mDynamicCodeLogger; final ViewCompiler mViewCompiler; @@ -1529,7 +1531,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService (i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(), i.getContext(), "*dexopt*"), (i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(), - i.getInstaller(), i.getInstallLock()), + i.getInstaller(), i.getInstallLock(), i.getDynamicCodeLogger()), + (i, pm) -> new DynamicCodeLogger(i.getInstaller()), (i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(), i.getInstallLock()), (i, pm) -> ApexManager.getInstance(), @@ -1711,6 +1714,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService mDefaultAppProvider = testParams.defaultAppProvider; mLegacyPermissionManager = testParams.legacyPermissionManagerInternal; mDexManager = testParams.dexManager; + mDynamicCodeLogger = testParams.dynamicCodeLogger; mFactoryTest = testParams.factoryTest; mIncrementalManager = testParams.incrementalManager; mInstallerService = testParams.installerService; @@ -1889,6 +1893,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService mPackageDexOptimizer = injector.getPackageDexOptimizer(); mDexManager = injector.getDexManager(); + mDynamicCodeLogger = injector.getDynamicCodeLogger(); mBackgroundDexOptService = injector.getBackgroundDexOptService(); mArtManagerService = injector.getArtManagerService(); mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper()); @@ -2316,6 +2321,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService .getList()); } mDexManager.load(userPackages); + mDynamicCodeLogger.load(userPackages); if (mIsUpgrade) { FrameworkStatsLog.write( FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, @@ -2980,9 +2986,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService return mDexManager; } + /*package*/ DynamicCodeLogger getDynamicCodeLogger() { + return mDynamicCodeLogger; + } + public void shutdown() { mCompilerStats.writeNow(); mDexManager.writePackageDexUsageNow(); + mDynamicCodeLogger.writeNow(); PackageWatchdog.getInstance(mContext).writeNow(); synchronized (mLock) { @@ -6346,6 +6357,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService return mDexManager; } + @NonNull + @Override + public DynamicCodeLogger getDynamicCodeLogger() { + return mDynamicCodeLogger; + } + @Override public boolean isPlatformSigned(String packageName) { PackageStateInternal packageState = snapshot().getPackageStateInternal(packageName); diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java index 76e6e45fc873..eb033cb343d4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java @@ -30,6 +30,7 @@ import com.android.server.SystemConfig; import com.android.server.compat.PlatformCompat; import com.android.server.pm.dex.ArtManagerService; import com.android.server.pm.dex.DexManager; +import com.android.server.pm.dex.DynamicCodeLogger; import com.android.server.pm.dex.ViewCompiler; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.permission.LegacyPermissionManagerInternal; @@ -106,6 +107,7 @@ public class PackageManagerServiceInjector { private final Singleton<PackageDexOptimizer> mPackageDexOptimizerProducer; private final Singleton<DexManager> mDexManagerProducer; + private final Singleton<DynamicCodeLogger> mDynamicCodeLoggerProducer; private final Singleton<ArtManagerService> mArtManagerServiceProducer; private final Singleton<ApexManager> mApexManagerProducer; @@ -154,6 +156,7 @@ public class PackageManagerServiceInjector { Producer<SystemConfig> systemConfigProducer, Producer<PackageDexOptimizer> packageDexOptimizerProducer, Producer<DexManager> dexManagerProducer, + Producer<DynamicCodeLogger> dynamicCodeLoggerProducer, Producer<ArtManagerService> artManagerServiceProducer, Producer<ApexManager> apexManagerProducer, Producer<ViewCompiler> viewCompilerProducer, @@ -200,6 +203,7 @@ public class PackageManagerServiceInjector { mPackageDexOptimizerProducer = new Singleton<>( packageDexOptimizerProducer); mDexManagerProducer = new Singleton<>(dexManagerProducer); + mDynamicCodeLoggerProducer = new Singleton<>(dynamicCodeLoggerProducer); mArtManagerServiceProducer = new Singleton<>( artManagerServiceProducer); mApexManagerProducer = new Singleton<>(apexManagerProducer); @@ -314,6 +318,10 @@ public class PackageManagerServiceInjector { return mDexManagerProducer.get(this, mPackageManager); } + public DynamicCodeLogger getDynamicCodeLogger() { + return mDynamicCodeLoggerProducer.get(this, mPackageManager); + } + public ArtManagerService getArtManagerService() { return mArtManagerServiceProducer.get(this, mPackageManager); } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java index bffbb84bcfae..0c617aef1ed6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java @@ -32,6 +32,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfig; import com.android.server.pm.dex.ArtManagerService; import com.android.server.pm.dex.DexManager; +import com.android.server.pm.dex.DynamicCodeLogger; import com.android.server.pm.dex.ViewCompiler; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.permission.LegacyPermissionManagerInternal; @@ -49,6 +50,7 @@ public final class PackageManagerServiceTestParams { public int defParseFlags; public DefaultAppProvider defaultAppProvider; public DexManager dexManager; + public DynamicCodeLogger dynamicCodeLogger; public List<ScanPartition> dirsToScanAsSystem; public boolean factoryTest; public ArrayMap<String, FeatureInfo> availableFeatures; diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index f1168f5ec272..849cbeba0300 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -172,6 +172,11 @@ class PackageManagerShellCommand extends ShellCommand { SUPPORTED_PERMISSION_FLAGS.put("revoke-when-requested", FLAG_PERMISSION_REVOKE_WHEN_REQUESTED); } + // For backward compatibility. DO NOT add new commands here. New ART Service commands should be + // added under the "art" namespace. + private static final Set<String> ART_SERVICE_COMMANDS = Set.of("compile", + "reconcile-secondary-dex-files", "force-dex-opt", "bg-dexopt-job", + "cancel-bg-dexopt-job", "delete-dexopt", "dump-profiles", "snapshot-profile", "art"); final IPackageManager mInterface; final LegacyPermissionManagerInternal mLegacyPermissionManager; @@ -250,22 +255,6 @@ class PackageManagerShellCommand extends ShellCommand { return runMovePackage(); case "move-primary-storage": return runMovePrimaryStorage(); - case "compile": - return runCompile(); - case "reconcile-secondary-dex-files": - return runreconcileSecondaryDexFiles(); - case "force-dex-opt": - return runForceDexOpt(); - case "bg-dexopt-job": - return runBgDexOpt(); - case "cancel-bg-dexopt-job": - return cancelBgDexOptJob(); - case "delete-dexopt": - return runDeleteDexOpt(); - case "dump-profiles": - return runDumpProfiles(); - case "snapshot-profile": - return runSnapshotProfile(); case "uninstall": return runUninstall(); case "clear": @@ -355,9 +344,19 @@ class PackageManagerShellCommand extends ShellCommand { return runBypassAllowedApexUpdateCheck(); case "set-silent-updates-policy": return runSetSilentUpdatesPolicy(); - case "art": - return runArtSubCommand(); default: { + if (ART_SERVICE_COMMANDS.contains(cmd)) { + if (DexOptHelper.useArtService()) { + return runArtServiceCommand(); + } else { + try { + return runLegacyDexoptCommand(cmd); + } catch (LegacyDexoptDisabledException e) { + throw new RuntimeException(e); + } + } + } + Boolean domainVerificationResult = mDomainVerificationShell.runCommand(this, cmd); if (domainVerificationResult != null) { @@ -381,12 +380,39 @@ class PackageManagerShellCommand extends ShellCommand { } } catch (RemoteException e) { pw.println("Remote exception: " + e); - } catch (ManagerNotFoundException e) { - pw.println(e); } return -1; } + private int runLegacyDexoptCommand(@NonNull String cmd) + throws RemoteException, LegacyDexoptDisabledException { + Installer.checkLegacyDexoptDisabled(); + switch (cmd) { + case "compile": + return runCompile(); + case "reconcile-secondary-dex-files": + return runreconcileSecondaryDexFiles(); + case "force-dex-opt": + return runForceDexOpt(); + case "bg-dexopt-job": + return runBgDexOpt(); + case "cancel-bg-dexopt-job": + return cancelBgDexOptJob(); + case "delete-dexopt": + return runDeleteDexOpt(); + case "dump-profiles": + return runDumpProfiles(); + case "snapshot-profile": + return runSnapshotProfile(); + case "art": + getOutPrintWriter().println("ART Service not enabled"); + return -1; + default: + // Can't happen. + throw new IllegalArgumentException(); + } + } + /** * Shows module info * @@ -3492,17 +3518,18 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - private int runArtSubCommand() throws ManagerNotFoundException { - // Remove the first arg "art" and forward to ART module. - String[] args = getAllArgs(); - args = Arrays.copyOfRange(args, 1, args.length); + private int runArtServiceCommand() { try (var in = ParcelFileDescriptor.dup(getInFileDescriptor()); var out = ParcelFileDescriptor.dup(getOutFileDescriptor()); var err = ParcelFileDescriptor.dup(getErrFileDescriptor())) { return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class) - .handleShellCommand(getTarget(), in, out, err, args); + .handleShellCommand(getTarget(), in, out, err, getAllArgs()); } catch (IOException e) { throw new IllegalStateException(e); + } catch (ManagerNotFoundException e) { + PrintWriter epw = getErrPrintWriter(); + epw.println("ART Service is not ready. Please try again later"); + return -1; } } @@ -4271,6 +4298,76 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(""); pw.println(" get-max-running-users"); pw.println(""); + pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT"); + pw.println(" Set the default home activity (aka launcher)."); + pw.println(" TARGET-COMPONENT can be a package name (com.package.my) or a full"); + pw.println(" component (com.package.my/component.name). However, only the package name"); + pw.println(" matters: the actual component used will be determined automatically from"); + pw.println(" the package."); + pw.println(""); + pw.println(" set-installer PACKAGE INSTALLER"); + pw.println(" Set installer package name"); + pw.println(""); + pw.println(" get-instantapp-resolver"); + pw.println( + " Return the name of the component that is the current instant app installer."); + pw.println(""); + pw.println(" set-harmful-app-warning [--user <USER_ID>] <PACKAGE> [<WARNING>]"); + pw.println(" Mark the app as harmful with the given warning message."); + pw.println(""); + pw.println(" get-harmful-app-warning [--user <USER_ID>] <PACKAGE>"); + pw.println(" Return the harmful app warning message for the given app, if present"); + pw.println(); + pw.println(" uninstall-system-updates [<PACKAGE>]"); + pw.println(" Removes updates to the given system application and falls back to its"); + pw.println(" /system version. Does nothing if the given package is not a system app."); + pw.println(" If no package is specified, removes updates to all system applications."); + pw.println(""); + pw.println(" get-moduleinfo [--all | --installed] [module-name]"); + pw.println(" Displays module info. If module-name is specified only that info is shown"); + pw.println(" By default, without any argument only installed modules are shown."); + pw.println(" --all: show all module info"); + pw.println(" --installed: show only installed modules"); + pw.println(""); + pw.println(" log-visibility [--enable|--disable] <PACKAGE>"); + pw.println(" Turns on debug logging when visibility is blocked for the given package."); + pw.println(" --enable: turn on debug logging (default)"); + pw.println(" --disable: turn off debug logging"); + pw.println(""); + pw.println(" set-silent-updates-policy [--allow-unlimited-silent-updates <INSTALLER>]"); + pw.println(" [--throttle-time <SECONDS>] [--reset]"); + pw.println(" Sets the policies of the silent updates."); + pw.println(" --allow-unlimited-silent-updates: allows unlimited silent updated"); + pw.println(" installation requests from the installer without the throttle time."); + pw.println(" --throttle-time: update the silent updates throttle time in seconds."); + pw.println(" --reset: restore the installer and throttle time to the default, and"); + pw.println(" clear tracks of silent updates in the system."); + pw.println(""); + if (DexOptHelper.useArtService()) { + printArtServiceHelp(); + } else { + printLegacyDexoptHelp(); + } + pw.println(""); + mDomainVerificationShell.printHelp(pw); + pw.println(""); + Intent.printIntentArgsHelp(pw, ""); + } + + private void printArtServiceHelp() { + final var ipw = new IndentingPrintWriter(getOutPrintWriter(), " " /* singleIndent */); + ipw.increaseIndent(); + try { + LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class) + .printShellCommandHelp(ipw); + } catch (ManagerNotFoundException e) { + ipw.println("ART Service is not ready. Please try again later"); + } + ipw.decreaseIndent(); + } + + private void printLegacyDexoptHelp() { + final PrintWriter pw = getOutPrintWriter(); pw.println(" compile [-m MODE | -r REASON] [-f] [-c] [--split SPLIT_NAME]"); pw.println(" [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)"); pw.println(" Trigger compilation of TARGET-PACKAGE or all packages if \"-a\". Options are:"); @@ -4343,57 +4440,6 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" " + ART_PROFILE_SNAPSHOT_DEBUG_LOCATION + "TARGET-PACKAGE[-code-path].prof"); pw.println(" If TARGET-PACKAGE=android it will take a snapshot of the boot image"); - pw.println(""); - pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT"); - pw.println(" Set the default home activity (aka launcher)."); - pw.println(" TARGET-COMPONENT can be a package name (com.package.my) or a full"); - pw.println(" component (com.package.my/component.name). However, only the package name"); - pw.println(" matters: the actual component used will be determined automatically from"); - pw.println(" the package."); - pw.println(""); - pw.println(" set-installer PACKAGE INSTALLER"); - pw.println(" Set installer package name"); - pw.println(""); - pw.println(" get-instantapp-resolver"); - pw.println(" Return the name of the component that is the current instant app installer."); - pw.println(""); - pw.println(" set-harmful-app-warning [--user <USER_ID>] <PACKAGE> [<WARNING>]"); - pw.println(" Mark the app as harmful with the given warning message."); - pw.println(""); - pw.println(" get-harmful-app-warning [--user <USER_ID>] <PACKAGE>"); - pw.println(" Return the harmful app warning message for the given app, if present"); - pw.println(); - pw.println(" uninstall-system-updates [<PACKAGE>]"); - pw.println(" Removes updates to the given system application and falls back to its"); - pw.println(" /system version. Does nothing if the given package is not a system app."); - pw.println(" If no package is specified, removes updates to all system applications."); - pw.println(""); - pw.println(" get-moduleinfo [--all | --installed] [module-name]"); - pw.println(" Displays module info. If module-name is specified only that info is shown"); - pw.println(" By default, without any argument only installed modules are shown."); - pw.println(" --all: show all module info"); - pw.println(" --installed: show only installed modules"); - pw.println(""); - pw.println(" log-visibility [--enable|--disable] <PACKAGE>"); - pw.println(" Turns on debug logging when visibility is blocked for the given package."); - pw.println(" --enable: turn on debug logging (default)"); - pw.println(" --disable: turn off debug logging"); - pw.println(""); - pw.println(" set-silent-updates-policy [--allow-unlimited-silent-updates <INSTALLER>]"); - pw.println(" [--throttle-time <SECONDS>] [--reset]"); - pw.println(" Sets the policies of the silent updates."); - pw.println(" --allow-unlimited-silent-updates: allows unlimited silent updated"); - pw.println(" installation requests from the installer without the throttle time."); - pw.println(" --throttle-time: update the silent updates throttle time in seconds."); - pw.println(" --reset: restore the installer and throttle time to the default, and"); - pw.println(" clear tracks of silent updates in the system."); - pw.println(""); - pw.println(" art [<SUB-COMMANDS>]"); - pw.println(" Invokes ART services commands. (Run `pm art help` for details.)"); - pw.println(""); - mDomainVerificationShell.printHelp(pw); - pw.println(""); - Intent.printIntentArgsHelp(pw , ""); } private static class LocalIntentReceiver { diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 3d4f7b0e4ecc..7f0c3f9f4f06 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -126,20 +126,21 @@ public class DexManager { private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex public DexManager(Context context, PackageDexOptimizer pdo, Installer installer, - Object installLock) { - this(context, pdo, installer, installLock, null); + Object installLock, DynamicCodeLogger dynamicCodeLogger) { + this(context, pdo, installer, installLock, dynamicCodeLogger, null); } @VisibleForTesting public DexManager(Context context, PackageDexOptimizer pdo, Installer installer, - Object installLock, @Nullable IPackageManager packageManager) { + Object installLock, DynamicCodeLogger dynamicCodeLogger, + @Nullable IPackageManager packageManager) { mContext = context; mPackageCodeLocationsCache = new HashMap<>(); mPackageDexUsage = new PackageDexUsage(); mPackageDexOptimizer = pdo; mInstaller = installer; mInstallLock = installLock; - mDynamicCodeLogger = new DynamicCodeLogger(installer); + mDynamicCodeLogger = dynamicCodeLogger; mPackageManager = packageManager; // This is currently checked to handle tests that pass in a null context. @@ -169,10 +170,6 @@ public class DexManager { return mPackageManager; } - public DynamicCodeLogger getDynamicCodeLogger() { - return mDynamicCodeLogger; - } - /** * Notify about dex files loads. * Note that this method is invoked when apps load dex files and it should @@ -328,7 +325,6 @@ public class DexManager { loadInternal(existingPackages); } catch (RuntimeException e) { mPackageDexUsage.clear(); - mDynamicCodeLogger.clear(); Slog.w(TAG, "Exception while loading. Starting with a fresh state.", e); } } @@ -379,12 +375,10 @@ public class DexManager { if (mPackageDexUsage.removePackage(packageName)) { mPackageDexUsage.maybeWriteAsync(); } - mDynamicCodeLogger.removePackage(packageName); } else { if (mPackageDexUsage.removeUserPackage(packageName, userId)) { mPackageDexUsage.maybeWriteAsync(); } - mDynamicCodeLogger.removeUserPackage(packageName, userId); } } @@ -463,14 +457,6 @@ public class DexManager { Slog.w(TAG, "Exception while loading package dex usage. " + "Starting with a fresh state.", e); } - - try { - mDynamicCodeLogger.readAndSync(packageToUsersMap); - } catch (RuntimeException e) { - mDynamicCodeLogger.clear(); - Slog.w(TAG, "Exception while loading package dynamic code usage. " - + "Starting with a fresh state.", e); - } } /** @@ -819,7 +805,6 @@ public class DexManager { */ public void writePackageDexUsageNow() { mPackageDexUsage.writeNow(); - mDynamicCodeLogger.writeNow(); } /** diff --git a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java index 9b94e993f967..da8fafaca5d8 100644 --- a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java +++ b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java @@ -43,6 +43,9 @@ import libcore.util.HexEncoding; import java.io.File; import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -64,7 +67,7 @@ public class DynamicCodeLogger { private final PackageDynamicCodeLoading mPackageDynamicCodeLoading; private final Installer mInstaller; - DynamicCodeLogger(Installer installer) { + public DynamicCodeLogger(Installer installer) { mInstaller = installer; mPackageDynamicCodeLoading = new PackageDynamicCodeLoading(); } @@ -220,8 +223,12 @@ public class DynamicCodeLogger { EventLog.writeEvent(SNET_TAG, subtag, uid, message); } - void recordDex(int loaderUserId, String dexPath, String owningPackageName, - String loadingPackageName) { + /** + * Records that an app running in the specified uid has executed dex code from the file at + * {@code path}. + */ + public void recordDex( + int loaderUserId, String dexPath, String owningPackageName, String loadingPackageName) { if (mPackageDynamicCodeLoading.record(owningPackageName, dexPath, FILE_TYPE_DEX, loaderUserId, loadingPackageName)) { mPackageDynamicCodeLoading.maybeWriteAsync(); @@ -229,8 +236,8 @@ public class DynamicCodeLogger { } /** - * Record that an app running in the specified uid has executed native code from the file at - * {@param path}. + * Records that an app running in the specified uid has executed native code from the file at + * {@code path}. */ public void recordNative(int loadingUid, String path) { String[] packages; @@ -274,7 +281,39 @@ public class DynamicCodeLogger { mPackageDynamicCodeLoading.syncData(packageToUsersMap); } - void writeNow() { + /** Writes the in-memory dynamic code information to disk right away. */ + public void writeNow() { mPackageDynamicCodeLoading.writeNow(); } + + /** Reads the dynamic code information from disk. */ + public void load(Map<Integer, List<PackageInfo>> userToPackagesMap) { + // Compute a reverse map. + Map<String, Set<Integer>> packageToUsersMap = new HashMap<>(); + for (Map.Entry<Integer, List<PackageInfo>> entry : userToPackagesMap.entrySet()) { + List<PackageInfo> packageInfoList = entry.getValue(); + int userId = entry.getKey(); + for (PackageInfo pi : packageInfoList) { + Set<Integer> users = + packageToUsersMap.computeIfAbsent(pi.packageName, k -> new HashSet<>()); + users.add(userId); + } + } + + readAndSync(packageToUsersMap); + } + + /** + * Notifies that the user {@code userId} data for package {@code packageName} was destroyed. + * This will remove all dynamic code information associated with the package for the given user. + * {@code userId} is allowed to be {@code UserHandle.USER_ALL} in which case + * all dynamic code information for the package will be removed. + */ + public void notifyPackageDataDestroyed(String packageName, int userId) { + if (userId == UserHandle.USER_ALL) { + removePackage(packageName); + } else { + removeUserPackage(packageName, userId); + } + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index 9935a2f2a0ba..06ba5dd6069b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -63,6 +63,7 @@ import com.android.server.SystemServerInitThreadPool import com.android.server.compat.PlatformCompat import com.android.server.extendedtestutils.wheneverStatic import com.android.server.pm.dex.DexManager +import com.android.server.pm.dex.DynamicCodeLogger import com.android.server.pm.parsing.PackageParser2 import com.android.server.pm.parsing.pkg.PackageImpl import com.android.server.pm.parsing.pkg.ParsedPackage @@ -208,6 +209,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { whenever(snapshot()) { appsFilterSnapshot } } val dexManager: DexManager = mock() + val dynamicCodeLogger: DynamicCodeLogger = mock() val installer: Installer = mock() val displayMetrics: DisplayMetrics = mock() val domainVerificationManagerInternal: DomainVerificationManagerInternal = mock() @@ -285,6 +287,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { whenever(mocks.injector.crossProfileIntentFilterHelper) .thenReturn(mocks.crossProfileIntentFilterHelper) whenever(mocks.injector.dexManager).thenReturn(mocks.dexManager) + whenever(mocks.injector.dynamicCodeLogger).thenReturn(mocks.dynamicCodeLogger) whenever(mocks.injector.systemConfig).thenReturn(mocks.systemConfig) whenever(mocks.injector.apexManager).thenReturn(mocks.apexManager) whenever(mocks.injector.scanningCachingPackageParser).thenReturn(mocks.packageParser) diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java index fb9cbb00255c..7dae23529fc6 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -85,6 +85,7 @@ public class DexManagerTests { private final Object mInstallLock = new Object(); + private DynamicCodeLogger mDynamicCodeLogger; private DexManager mDexManager; private TestData mFooUser0; @@ -158,8 +159,9 @@ public class DexManagerTests { .when(mockContext) .getSystemService(PowerManager.class); - mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null, - mInstaller, mInstallLock, mPM); + mDynamicCodeLogger = new DynamicCodeLogger(mInstaller); + mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null, mInstaller, + mInstallLock, mDynamicCodeLogger, mPM); // Foo and Bar are available to user0. // Only Bar is available to user1; @@ -452,6 +454,7 @@ public class DexManagerTests { notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0); + mDynamicCodeLogger.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0); // Data for user 1 should still be present PackageUseInfo pui = getPackageUseInfo(mBarUser1); @@ -474,6 +477,7 @@ public class DexManagerTests { notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); + mDynamicCodeLogger.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); // Foo should still be around since it's used by other apps but with no // secondary dex info. @@ -491,6 +495,7 @@ public class DexManagerTests { notifyDexLoad(mFooUser0, fooSecondaries, mUser0); mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); + mDynamicCodeLogger.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); // Foo should not be around since all its secondary dex info were deleted // and it is not used by other apps. @@ -505,6 +510,8 @@ public class DexManagerTests { notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL); + mDynamicCodeLogger.notifyPackageDataDestroyed( + mBarUser0.getPackageName(), UserHandle.USER_ALL); // Bar should not be around since it was removed for all users. assertNoUseInfo(mBarUser0); @@ -906,8 +913,7 @@ public class DexManagerTests { } private PackageDynamicCode getPackageDynamicCodeInfo(TestData testData) { - return mDexManager.getDynamicCodeLogger() - .getPackageDynamicCodeInfo(testData.getPackageName()); + return mDynamicCodeLogger.getPackageDynamicCodeInfo(testData.getPackageName()); } private void assertNoUseInfo(TestData testData) { |