diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index fb8ded1e7a43c..f38c80cb89cdb 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2855,4 +2855,13 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public boolean isPackageStateProtected(String packageName, int userId) { + try { + return mPM.isPackageStateProtected(packageName, userId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 9a19133e7703f..d43d80f0f678f 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -674,4 +674,6 @@ interface IPackageManager { boolean hasUidSigningCertificate(int uid, in byte[] signingCertificate, int flags); String getSystemTextClassifierPackageName(); + + boolean isPackageStateProtected(String packageName, int userId); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 4d8773c27d932..114c485e08cdc 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -6140,4 +6140,16 @@ public abstract class PackageManager { throw new UnsupportedOperationException( "getSystemTextClassifierPackageName not implemented in subclass"); } + + /** + * @return whether a given package's state is protected, e.g. package cannot be disabled, + * suspended, hidden or force stopped. + * + * @hide + */ + public boolean isPackageStateProtected(String packageName, int userId) { + throw new UnsupportedOperationException( + "isPackageStateProtected not implemented in subclass"); + } + } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1b8fc42619d88..1c565edc477f7 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17,6 +17,7 @@ package com.android.server.pm; import static android.Manifest.permission.DELETE_PACKAGES; +import static android.Manifest.permission.MANAGE_DEVICE_ADMINS; import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS; import static android.Manifest.permission.INSTALL_PACKAGES; import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS; @@ -115,6 +116,7 @@ import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; @@ -24326,6 +24328,23 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return mSettings.getHarmfulAppWarningLPr(packageName, userId); } } + + @Override + public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) { + final int callingUid = Binder.getCallingUid(); + final int callingAppId = UserHandle.getAppId(callingUid); + + mPermissionManager.enforceCrossUserPermission(callingUid, userId, + false /*requireFullPermission*/, true /*checkShell*/, "isPackageStateProtected"); + + if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID + && checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid) != PERMISSION_GRANTED) { + throw new SecurityException("Caller must have the " + + MANAGE_DEVICE_ADMINS + " permission."); + } + + return mProtectedPackages.isPackageStateProtected(userId, packageName); + } } interface PackageSender {