diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java index b76140cb6f955..8c33dd935822d 100644 --- a/services/core/java/com/android/server/pm/DexOptHelper.java +++ b/services/core/java/com/android/server/pm/DexOptHelper.java @@ -442,10 +442,13 @@ final class DexOptHelper { } } - public boolean performDexOptMode(String packageName, + public boolean performDexOptMode(@NonNull Computer snapshot, String packageName, boolean checkProfiles, String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) { - PackageManagerServiceUtils.enforceSystemOrRootOrShell("performDexOptMode"); + if (!PackageManagerServiceUtils.isSystemOrRootOrShell() + && !isCallerInstallerForPackage(snapshot, packageName)) { + throw new SecurityException("performDexOptMode"); + } int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) | (force ? DexoptOptions.DEXOPT_FORCE : 0) @@ -454,6 +457,22 @@ final class DexOptHelper { targetCompilerFilter, splitName, flags)); } + private boolean isCallerInstallerForPackage(@NonNull Computer snapshot, String packageName) { + final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); + if (packageState == null) { + return false; + } + final InstallSource installSource = packageState.getInstallSource(); + + final PackageStateInternal installerPackageState = + snapshot.getPackageStateInternal(installSource.installerPackageName); + if (installerPackageState == null) { + return false; + } + final AndroidPackage installerPkg = installerPackageState.getPkg(); + return installerPkg.getUid() == Binder.getCallingUid(); + } + public boolean performDexOptSecondary(String packageName, String compilerFilter, boolean force) { int flags = DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index ba7309f0283d2..043661302f8f7 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -972,8 +972,9 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { public final boolean performDexOptMode(String packageName, boolean checkProfiles, String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) { - return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter, - force, bootComplete, splitName); + final Computer snapshot = snapshot(); + return mDexOptHelper.performDexOptMode(snapshot, packageName, checkProfiles, + targetCompilerFilter, force, bootComplete, splitName); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 2a1a99068d45d..4d11b13510e99 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -1245,12 +1245,19 @@ public class PackageManagerServiceUtils { * @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) { + if (!isSystemOrRootOrShell()) { throw new SecurityException(message); } } + /** + * Check if the Binder caller is system UID, root's UID, or shell's UID. + */ + public static boolean isSystemOrRootOrShell() { + final int uid = Binder.getCallingUid(); + return uid == Process.SYSTEM_UID || uid == Process.ROOT_UID || uid == Process.SHELL_UID; + } + /** * Check if the Binder caller is system UID or root's UID. */