diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ed6dea815e4c9..6d564a3ce61c7 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -6681,8 +6681,7 @@ public final class ActivityThread extends ClientTransactionHandler { private InstrumentationInfo prepareInstrumentation(AppBindData data) { final InstrumentationInfo ii; try { - ii = new ApplicationPackageManager( - null, getPackageManager(), getPermissionManager()) + ii = new ApplicationPackageManager(null, getPackageManager()) .getInstrumentationInfo(data.instrumentationName, 0); } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 3642d318e8209..186d1fede5e0d 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -59,8 +59,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PackageManager.Property; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; @@ -95,8 +93,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; -import android.permission.IOnPermissionsChangeListener; -import android.permission.IPermissionManager; import android.permission.PermissionManager; import android.provider.Settings; import android.system.ErrnoException; @@ -106,7 +102,6 @@ import android.system.StructStat; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.DebugUtils; import android.util.LauncherIcons; import android.util.Log; @@ -129,7 +124,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; @@ -137,14 +131,6 @@ import java.util.Set; public class ApplicationPackageManager extends PackageManager { private static final String TAG = "ApplicationPackageManager"; private static final boolean DEBUG_ICONS = false; - /** - * Note: Changing this won't do anything on it's own - you should also change the filtering in - * {@link #shouldTraceGrant} - * - * @hide - */ - public static final boolean DEBUG_TRACE_GRANTS = false; - public static final boolean DEBUG_TRACE_PERMISSION_UPDATES = false; private static final int DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES = 16384; // 16KB @@ -171,6 +157,8 @@ public class ApplicationPackageManager extends PackageManager { @GuardedBy("mLock") private UserManager mUserManager; @GuardedBy("mLock") + private PermissionManager mPermissionManager; + @GuardedBy("mLock") private PackageInstaller mInstaller; @GuardedBy("mLock") private ArtManager mArtManager; @@ -190,6 +178,15 @@ public class ApplicationPackageManager extends PackageManager { } } + private PermissionManager getPermissionManager() { + synchronized (mLock) { + if (mPermissionManager == null) { + mPermissionManager = mContext.getSystemService(PermissionManager.class); + } + return mPermissionManager; + } + } + @Override public int getUserId() { return mContext.getUserId(); @@ -355,66 +352,41 @@ public class ApplicationPackageManager extends PackageManager { @Override @SuppressWarnings("unchecked") public List getAllPermissionGroups(int flags) { - try { - final ParceledListSlice parceledList = - mPermissionManager.getAllPermissionGroups(flags); - if (parceledList == null) { - return Collections.emptyList(); - } - return parceledList.getList(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().getAllPermissionGroups(flags); } @Override public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) throws NameNotFoundException { - try { - final PermissionGroupInfo pgi = - mPermissionManager.getPermissionGroupInfo(groupName, flags); - if (pgi != null) { - return pgi; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + final PermissionGroupInfo permissionGroupInfo = getPermissionManager() + .getPermissionGroupInfo(groupName, flags); + if (permissionGroupInfo == null) { + throw new NameNotFoundException(groupName); } - throw new NameNotFoundException(groupName); + return permissionGroupInfo; } @Override public PermissionInfo getPermissionInfo(String permName, int flags) throws NameNotFoundException { - try { - final String packageName = mContext.getOpPackageName(); - final PermissionInfo pi = - mPermissionManager.getPermissionInfo(permName, packageName, flags); - if (pi != null) { - return pi; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + final PermissionInfo permissionInfo = getPermissionManager().getPermissionInfo(permName, + flags); + if (permissionInfo == null) { + throw new NameNotFoundException(permName); } - throw new NameNotFoundException(permName); + return permissionInfo; } @Override @SuppressWarnings("unchecked") public List queryPermissionsByGroup(String groupName, int flags) throws NameNotFoundException { - try { - final ParceledListSlice parceledList = - mPermissionManager.queryPermissionsByGroup(groupName, flags); - if (parceledList != null) { - final List pi = parceledList.getList(); - if (pi != null) { - return pi; - } - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + final List permissionInfos = getPermissionManager().queryPermissionsByGroup( + groupName, flags); + if (permissionInfos == null) { + throw new NameNotFoundException(groupName); } - throw new NameNotFoundException(groupName); + return permissionInfos; } @Override @@ -724,11 +696,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean isPermissionRevokedByPolicy(String permName, String pkgName) { - try { - return mPermissionManager.isPermissionRevokedByPolicy(permName, pkgName, getUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().isPermissionRevokedByPolicy(pkgName, permName); } /** @@ -750,50 +718,23 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean addPermission(PermissionInfo info) { - try { - return mPermissionManager.addPermission(info, false); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().addPermission(info, false); } @Override public boolean addPermissionAsync(PermissionInfo info) { - try { - return mPermissionManager.addPermission(info, true); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().addPermission(info, true); } @Override public void removePermission(String name) { - try { - mPermissionManager.removePermission(name); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getPermissionManager().removePermission(name); } @Override public void grantRuntimePermission(String packageName, String permissionName, UserHandle user) { - if (DEBUG_TRACE_GRANTS - && shouldTraceGrant(packageName, permissionName, user.getIdentifier())) { - Log.i(TAG, "App " + mContext.getPackageName() + " is granting " + packageName + " " - + permissionName + " for user " + user.getIdentifier(), new RuntimeException()); - } - try { - mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** @hide */ - public static boolean shouldTraceGrant(String packageName, String permissionName, int userId) { - // To be modified when debugging - return false; + getPermissionManager().grantRuntimePermission(packageName, permissionName, user); } @Override @@ -804,124 +745,55 @@ public class ApplicationPackageManager extends PackageManager { @Override public void revokeRuntimePermission(String packageName, String permName, UserHandle user, String reason) { - if (DEBUG_TRACE_PERMISSION_UPDATES - && shouldTraceGrant(packageName, permName, user.getIdentifier())) { - Log.i(TAG, "App " + mContext.getPackageName() + " is revoking " + packageName + " " - + permName + " for user " + user.getIdentifier() + " with reason " + reason, - new RuntimeException()); - } - try { - mPermissionManager - .revokeRuntimePermission(packageName, permName, user.getIdentifier(), reason); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getPermissionManager().revokeRuntimePermission(packageName, permName, user, reason); } @Override public int getPermissionFlags(String permName, String packageName, UserHandle user) { - try { - return mPermissionManager - .getPermissionFlags(permName, packageName, user.getIdentifier()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().getPermissionFlags(packageName, permName, user); } @Override public void updatePermissionFlags(String permName, String packageName, int flagMask, int flagValues, UserHandle user) { - if (DEBUG_TRACE_PERMISSION_UPDATES - && shouldTraceGrant(packageName, permName, user.getIdentifier())) { - Log.i(TAG, "App " + mContext.getPackageName() + " is updating flags for " - + packageName + " " - + permName + " for user " + user.getIdentifier() + ": " - + DebugUtils.flagsToString(PackageManager.class, "FLAG_PERMISSION_", flagMask) - + " := " + DebugUtils.flagsToString( - PackageManager.class, "FLAG_PERMISSION_", flagValues), - new RuntimeException()); - } - try { - final boolean checkAdjustPolicyFlagPermission = - mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q; - mPermissionManager.updatePermissionFlags(permName, packageName, flagMask, - flagValues, checkAdjustPolicyFlagPermission, user.getIdentifier()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getPermissionManager().updatePermissionFlags(packageName, permName, flagMask, flagValues, + user); } @Override public @NonNull Set getWhitelistedRestrictedPermissions( @NonNull String packageName, @PermissionWhitelistFlags int flags) { - try { - final int userId = getUserId(); - final List whitelist = mPermissionManager - .getWhitelistedRestrictedPermissions(packageName, flags, userId); - if (whitelist != null) { - return new ArraySet<>(whitelist); - } - return Collections.emptySet(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().getAllowlistedRestrictedPermissions(packageName, flags); } @Override public boolean addWhitelistedRestrictedPermission(@NonNull String packageName, @NonNull String permName, @PermissionWhitelistFlags int flags) { - try { - final int userId = getUserId(); - return mPermissionManager - .addWhitelistedRestrictedPermission(packageName, permName, flags, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().addAllowlistedRestrictedPermission(packageName, permName, + flags); } @Override - public boolean setAutoRevokeWhitelisted( - @NonNull String packageName, boolean whitelisted) { - try { - final int userId = getUserId(); - return mPermissionManager.setAutoRevokeWhitelisted(packageName, whitelisted, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + public boolean setAutoRevokeWhitelisted(@NonNull String packageName, boolean whitelisted) { + return getPermissionManager().setAutoRevokeExempted(packageName, whitelisted); } @Override public boolean isAutoRevokeWhitelisted(@NonNull String packageName) { - try { - final int userId = getUserId(); - return mPermissionManager.isAutoRevokeWhitelisted(packageName, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().isAutoRevokeExempted(packageName); } @Override public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName, @NonNull String permName, @PermissionWhitelistFlags int flags) { - try { - final int userId = getUserId(); - return mPermissionManager - .removeWhitelistedRestrictedPermission(packageName, permName, flags, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().removeAllowlistedRestrictedPermission(packageName, permName, + flags); } @Override @UnsupportedAppUsage public boolean shouldShowRequestPermissionRationale(String permName) { - try { - final String packageName = mContext.getPackageName(); - return mPermissionManager - .shouldShowRequestPermissionRationale(permName, packageName, getUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().shouldShowRequestPermissionRationale(permName); } @Override @@ -1880,34 +1752,12 @@ public class ApplicationPackageManager extends PackageManager { @Override public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) { - synchronized (mPermissionListeners) { - if (mPermissionListeners.get(listener) != null) { - return; - } - OnPermissionsChangeListenerDelegate delegate = - new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper()); - try { - mPermissionManager.addOnPermissionsChangeListener(delegate); - mPermissionListeners.put(listener, delegate); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + getPermissionManager().addOnPermissionsChangeListener(listener); } @Override public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) { - synchronized (mPermissionListeners) { - IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener); - if (delegate != null) { - try { - mPermissionManager.removeOnPermissionsChangeListener(delegate); - mPermissionListeners.remove(listener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } + getPermissionManager().removeOnPermissionsChangeListener(listener); } @UnsupportedAppUsage @@ -1918,11 +1768,9 @@ public class ApplicationPackageManager extends PackageManager { } } - protected ApplicationPackageManager(ContextImpl context, IPackageManager pm, - IPermissionManager permissionManager) { + protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; mPM = pm; - mPermissionManager = permissionManager; } /** @@ -3234,7 +3082,6 @@ public class ApplicationPackageManager extends PackageManager { private final ContextImpl mContext; @UnsupportedAppUsage private final IPackageManager mPM; - private final IPermissionManager mPermissionManager; /** Assume locked until we hear otherwise */ private volatile boolean mUserUnlocked = false; @@ -3245,41 +3092,6 @@ public class ApplicationPackageManager extends PackageManager { private static ArrayMap> sStringCache = new ArrayMap>(); - private final Map - mPermissionListeners = new ArrayMap<>(); - - public class OnPermissionsChangeListenerDelegate extends IOnPermissionsChangeListener.Stub - implements Handler.Callback{ - private static final int MSG_PERMISSIONS_CHANGED = 1; - - private final OnPermissionsChangedListener mListener; - private final Handler mHandler; - - - public OnPermissionsChangeListenerDelegate(OnPermissionsChangedListener listener, - Looper looper) { - mListener = listener; - mHandler = new Handler(looper, this); - } - - @Override - public void onPermissionsChanged(int uid) { - mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget(); - } - - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_PERMISSIONS_CHANGED: { - final int uid = msg.arg1; - mListener.onPermissionsChanged(uid); - return true; - } - } - return false; - } - } - @Override public boolean canRequestPackageInstalls() { try { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 2fec9f79717a2..124cf71edc9c0 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -72,7 +72,6 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; -import android.permission.IPermissionManager; import android.permission.PermissionManager; import android.system.ErrnoException; import android.system.Os; @@ -370,10 +369,9 @@ class ContextImpl extends Context { } final IPackageManager pm = ActivityThread.getPackageManager(); - final IPermissionManager permissionManager = ActivityThread.getPermissionManager(); - if (pm != null && permissionManager != null) { + if (pm != null) { // Doesn't matter if we make more than one instance. - return (mPackageManager = new ApplicationPackageManager(this, pm, permissionManager)); + return (mPackageManager = new ApplicationPackageManager(this, pm)); } return null; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index cf3f7069c63f3..67a1ad6763487 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4438,6 +4438,7 @@ public abstract class PackageManager { * @throws NameNotFoundException if a package with the given name cannot be * found on the system. */ + //@Deprecated public abstract PermissionInfo getPermissionInfo(@NonNull String permName, @PermissionInfoFlags int flags) throws NameNotFoundException; @@ -4450,9 +4451,10 @@ public abstract class PackageManager { * @param flags Additional option flags to modify the data returned. * @return Returns a list of {@link PermissionInfo} containing information * about all of the permissions in the given group. - * @throws NameNotFoundException if a package with the given name cannot be + * @throws NameNotFoundException if a group with the given name cannot be * found on the system. */ + //@Deprecated @NonNull public abstract List queryPermissionsByGroup(@NonNull String permissionGroup, @PermissionInfoFlags int flags) throws NameNotFoundException; @@ -4481,7 +4483,7 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular group of * permissions. * - * @param permName The fully qualified name (i.e. + * @param groupName The fully qualified name (i.e. * com.google.permission_group.APPS) of the permission you are * interested in. * @param flags Additional option flags to modify the data returned. @@ -4490,8 +4492,9 @@ public abstract class PackageManager { * @throws NameNotFoundException if a package with the given name cannot be * found on the system. */ + //@Deprecated @NonNull - public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String permName, + public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String groupName, @PermissionGroupInfoFlags int flags) throws NameNotFoundException; /** @@ -4501,6 +4504,7 @@ public abstract class PackageManager { * @return Returns a list of {@link PermissionGroupInfo} containing * information about all of the known permission groups. */ + //@Deprecated @NonNull public abstract List getAllPermissionGroups( @PermissionGroupInfoFlags int flags); @@ -4757,6 +4761,7 @@ public abstract class PackageManager { * @return Whether the permission is restricted by policy. */ @CheckResult + //@Deprecated public abstract boolean isPermissionRevokedByPolicy(@NonNull String permName, @NonNull String packageName); @@ -4805,6 +4810,7 @@ public abstract class PackageManager { * * @see #removePermission(String) */ + //@Deprecated public abstract boolean addPermission(@NonNull PermissionInfo info); /** @@ -4814,6 +4820,7 @@ public abstract class PackageManager { * expense of no guarantee the added permission will be retained if * the device is rebooted before it is written. */ + //@Deprecated public abstract boolean addPermissionAsync(@NonNull PermissionInfo info); /** @@ -4829,6 +4836,7 @@ public abstract class PackageManager { * * @see #addPermission(PermissionInfo) */ + //@Deprecated public abstract void removePermission(@NonNull String permName); /** @@ -4881,6 +4889,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) @@ -4908,6 +4917,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) @@ -4936,6 +4946,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String packageName, @@ -4953,6 +4964,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(anyOf = { @@ -4976,6 +4988,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(anyOf = { @@ -5040,6 +5053,7 @@ public abstract class PackageManager { * * @throws SecurityException if you try to access a whitelist that you have no access to. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, conditional = true) public @NonNull Set getWhitelistedRestrictedPermissions( @@ -5106,6 +5120,7 @@ public abstract class PackageManager { * * @throws SecurityException if you try to modify a whitelist that you have no access to. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, conditional = true) public boolean addWhitelistedRestrictedPermission(@NonNull String packageName, @@ -5175,6 +5190,7 @@ public abstract class PackageManager { * * @throws SecurityException if you try to modify a whitelist that you have no access to. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, conditional = true) public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName, @@ -5207,6 +5223,7 @@ public abstract class PackageManager { * * @throws SecurityException if you you have no access to modify this. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, conditional = true) public boolean setAutoRevokeWhitelisted(@NonNull String packageName, boolean whitelisted) { @@ -5234,6 +5251,7 @@ public abstract class PackageManager { * * @throws SecurityException if you you have no access to this. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, conditional = true) public boolean isAutoRevokeWhitelisted(@NonNull String packageName) { @@ -5252,6 +5270,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @UnsupportedAppUsage public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permName); @@ -7554,6 +7573,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) @@ -7567,6 +7587,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 3940bd62950cf..d31e0129fb27f 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -19,6 +19,7 @@ package android.permission; import static android.os.Build.VERSION_CODES.S; import android.Manifest; +import android.annotation.CheckResult; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -36,11 +37,22 @@ import android.compat.annotation.EnabledAfter; import android.content.Context; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; import android.content.pm.permission.SplitPermissionInfoParcelable; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.DebugUtils; +import android.util.Log; import android.util.Slog; import com.android.internal.annotations.Immutable; @@ -60,7 +72,7 @@ import java.util.Set; @SystemApi @SystemService(Context.PERMISSION_SERVICE) public final class PermissionManager { - private static final String TAG = PermissionManager.class.getName(); + private static final String LOG_TAG = PermissionManager.class.getName(); /** @hide */ public static final String KILL_APP_REASON_PERMISSIONS_REVOKED = @@ -80,6 +92,18 @@ public final class PermissionManager { @EnabledAfter(targetSdkVersion = S) public static final long CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS = 146211400; + /** + * Note: Changing this won't do anything on its own - you should also change the filtering in + * {@link #shouldTraceGrant}. + * + * @hide + */ + public static final boolean DEBUG_TRACE_GRANTS = false; + /** + * @hide + */ + public static final boolean DEBUG_TRACE_PERMISSION_UPDATES = false; + private final @NonNull Context mContext; private final IPackageManager mPackageManager; @@ -88,6 +112,9 @@ public final class PermissionManager { private final LegacyPermissionManager mLegacyPermissionManager; + private final ArrayMap mPermissionListeners = new ArrayMap<>(); + private List mSplitPermissionInfos; /** @@ -106,6 +133,649 @@ public final class PermissionManager { mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class); } + /** + * Retrieve all of the information we know about a particular permission. + * + * @param permissionName the fully qualified name (e.g. com.android.permission.LOGIN) of the + * permission you are interested in + * @param flags additional option flags to modify the data returned + * @return a {@link PermissionInfo} containing information about the permission, or {@code null} + * if not found + * + * @hide Pending API + */ + @Nullable + public PermissionInfo getPermissionInfo(@NonNull String permissionName, + @PackageManager.PermissionInfoFlags int flags) { + try { + final String packageName = mContext.getOpPackageName(); + return mPermissionManager.getPermissionInfo(permissionName, packageName, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Query for all of the permissions associated with a particular group. + * + * @param groupName the fully qualified name (e.g. com.android.permission.LOGIN) of the + * permission group you are interested in. Use {@code null} to find all of the + * permissions not associated with a group + * @param flags additional option flags to modify the data returned + * @return a list of {@link PermissionInfo} containing information about all of the permissions + * in the given group, or {@code null} if the group is not found + * + * @hide Pending API + */ + @Nullable + public List queryPermissionsByGroup(@NonNull String groupName, + @PackageManager.PermissionInfoFlags int flags) { + try { + final ParceledListSlice parceledList = + mPermissionManager.queryPermissionsByGroup(groupName, flags); + if (parceledList == null) { + return null; + } + return parceledList.getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Add a new dynamic permission to the system. For this to work, your package must have defined + * a permission tree through the + * {@link android.R.styleable#AndroidManifestPermissionTree <permission-tree>} tag in its + * manifest. A package can only add permissions to trees that were defined by either its own + * package or another with the same user id; a permission is in a tree if it matches the name of + * the permission tree + ".": for example, "com.foo.bar" is a member of the permission tree + * "com.foo". + *

+ * It is good to make your permission tree name descriptive, because you are taking possession + * of that entire set of permission names. Thus, it must be under a domain you control, with a + * suffix that will not match any normal permissions that may be declared in any applications + * that are part of that domain. + *

+ * New permissions must be added before any .apks are installed that use those permissions. + * Permissions you add through this method are remembered across reboots of the device. If the + * given permission already exists, the info you supply here will be used to update it. + * + * @param permissionInfo description of the permission to be added + * @param async whether the persistence of the permission should be asynchronous, allowing it to + * return quicker and batch a series of adds, at the expense of no guarantee the + * added permission will be retained if the device is rebooted before it is + * written. + * @return {@code true} if a new permission was created, {@code false} if an existing one was + * updated + * @throws SecurityException if you are not allowed to add the given permission name + * + * @see #removePermission(String) + * + * @hide Pending API + */ + public boolean addPermission(@NonNull PermissionInfo permissionInfo, boolean async) { + try { + return mPermissionManager.addPermission(permissionInfo, async); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Removes a permission that was previously added with + * {@link #addPermission(PermissionInfo, boolean)}. The same ownership rules apply -- you are + * only allowed to remove permissions that you are allowed to add. + * + * @param permissionName the name of the permission to remove + * @throws SecurityException if you are not allowed to remove the given permission name + * + * @see #addPermission(PermissionInfo, boolean) + * + * @hide Pending API + */ + public void removePermission(@NonNull String permissionName) { + try { + mPermissionManager.removePermission(permissionName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieve all of the information we know about a particular group of permissions. + * + * @param groupName the fully qualified name (e.g. com.android.permission_group.APPS) of the + * permission you are interested in + * @param flags additional option flags to modify the data returned + * @return a {@link PermissionGroupInfo} containing information about the permission, or + * {@code null} if not found + * + * @hide Pending API + */ + @Nullable + public PermissionGroupInfo getPermissionGroupInfo(@NonNull String groupName, + @PackageManager.PermissionGroupInfoFlags int flags) { + try { + return mPermissionManager.getPermissionGroupInfo(groupName, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieve all of the known permission groups in the system. + * + * @param flags additional option flags to modify the data returned + * @return a list of {@link PermissionGroupInfo} containing information about all of the known + * permission groups + * + * @hide Pending API + */ + @NonNull + public List getAllPermissionGroups( + @PackageManager.PermissionGroupInfoFlags int flags) { + try { + final ParceledListSlice parceledList = + mPermissionManager.getAllPermissionGroups(flags); + if (parceledList == null) { + return Collections.emptyList(); + } + return parceledList.getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Checks whether a particular permissions has been revoked for a package by policy. Typically + * the device owner or the profile owner may apply such a policy. The user cannot grant policy + * revoked permissions, hence the only way for an app to get such a permission is by a policy + * change. + * + * @param packageName the name of the package you are checking against + * @param permissionName the name of the permission you are checking for + * + * @return whether the permission is restricted by policy + * + * @hide Pending API + */ + @CheckResult + public boolean isPermissionRevokedByPolicy(@NonNull String packageName, + @NonNull String permissionName) { + try { + return mPermissionManager.isPermissionRevokedByPolicy(permissionName, packageName, + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public static boolean shouldTraceGrant(String packageName, String permissionName, int userId) { + // To be modified when debugging + return false; + } + + /** + * Grant a runtime permission to an application which the application does not already have. The + * permission must have been requested by the application. If the application is not allowed to + * hold the permission, a {@link java.lang.SecurityException} is thrown. If the package or + * permission is invalid, a {@link java.lang.IllegalArgumentException} is thrown. + *

+ * Note: Using this API requires holding + * {@code android.permission.GRANT_RUNTIME_PERMISSIONS} and if the user ID is not the current + * user {@code android.permission.INTERACT_ACROSS_USERS_FULL}. + * + * @param packageName the package to which to grant the permission + * @param permissionName the permission name to grant + * @param user the user for which to grant the permission + * + * @see #revokeRuntimePermission(String, String, android.os.UserHandle) + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) + //@SystemApi + public void grantRuntimePermission(@NonNull String packageName, + @NonNull String permissionName, @NonNull UserHandle user) { + if (DEBUG_TRACE_GRANTS + && shouldTraceGrant(packageName, permissionName, user.getIdentifier())) { + Log.i(LOG_TAG, "App " + mContext.getPackageName() + " is granting " + packageName + " " + + permissionName + " for user " + user.getIdentifier(), new RuntimeException()); + } + try { + mPermissionManager.grantRuntimePermission(packageName, permissionName, + user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Revoke a runtime permission that was previously granted by + * {@link #grantRuntimePermission(String, String, android.os.UserHandle)}. The permission must + * have been requested by and granted to the application. If the application is not allowed to + * hold the permission, a {@link java.lang.SecurityException} is thrown. If the package or + * permission is invalid, a {@link java.lang.IllegalArgumentException} is thrown. + *

+ * Note: Using this API requires holding + * {@code android.permission.REVOKE_RUNTIME_PERMISSIONS} and if the user ID is not the current + * user {@code android.permission.INTERACT_ACROSS_USERS_FULL}. + * + * @param packageName the package from which to revoke the permission + * @param permName the permission name to revoke + * @param user the user for which to revoke the permission + * @param reason the reason for the revoke, or {@code null} for unspecified + * + * @see #grantRuntimePermission(String, String, android.os.UserHandle) + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) + //@SystemApi + public void revokeRuntimePermission(@NonNull String packageName, + @NonNull String permName, @NonNull UserHandle user, @Nullable String reason) { + if (DEBUG_TRACE_PERMISSION_UPDATES + && shouldTraceGrant(packageName, permName, user.getIdentifier())) { + Log.i(LOG_TAG, "App " + mContext.getPackageName() + " is revoking " + packageName + " " + + permName + " for user " + user.getIdentifier() + " with reason " + + reason, new RuntimeException()); + } + try { + mPermissionManager + .revokeRuntimePermission(packageName, permName, user.getIdentifier(), reason); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the state flags associated with a permission. + * + * @param packageName the package name for which to get the flags + * @param permissionName the permission for which to get the flags + * @param user the user for which to get permission flags + * @return the permission flags + * + * @hide + */ + @PackageManager.PermissionFlags + @RequiresPermission(anyOf = { + android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, + android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, + android.Manifest.permission.GET_RUNTIME_PERMISSIONS + }) + //@SystemApi + public int getPermissionFlags(@NonNull String packageName, @NonNull String permissionName, + @NonNull UserHandle user) { + try { + return mPermissionManager.getPermissionFlags(permissionName, packageName, + user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Updates the flags associated with a permission by replacing the flags in the specified mask + * with the provided flag values. + * + * @param packageName The package name for which to update the flags + * @param permissionName The permission for which to update the flags + * @param flagMask The flags which to replace + * @param flagValues The flags with which to replace + * @param user The user for which to update the permission flags + * + * @hide + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, + android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS + }) + //@SystemApi + public void updatePermissionFlags(@NonNull String packageName, @NonNull String permissionName, + @PackageManager.PermissionFlags int flagMask, + @PackageManager.PermissionFlags int flagValues, @NonNull UserHandle user) { + if (DEBUG_TRACE_PERMISSION_UPDATES && shouldTraceGrant(packageName, permissionName, + user.getIdentifier())) { + Log.i(LOG_TAG, "App " + mContext.getPackageName() + " is updating flags for " + + packageName + " " + permissionName + " for user " + + user.getIdentifier() + ": " + DebugUtils.flagsToString( + PackageManager.class, "FLAG_PERMISSION_", flagMask) + " := " + + DebugUtils.flagsToString(PackageManager.class, "FLAG_PERMISSION_", + flagValues), new RuntimeException()); + } + try { + final boolean checkAdjustPolicyFlagPermission = + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q; + mPermissionManager.updatePermissionFlags(permissionName, packageName, flagMask, + flagValues, checkAdjustPolicyFlagPermission, user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the restricted permissions that have been allowlisted and the app is allowed to have + * them granted in their full form. + *

+ * Permissions can be hard restricted which means that the app cannot hold them or soft + * restricted where the app can hold the permission but in a weaker form. Whether a permission + * is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard restricted} or + * {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} depends on the permission + * declaration. Allowlisting a hard restricted permission allows for the to hold that permission + * and allowlisting a soft restricted permission allows the app to hold the permission in its + * full, unrestricted form. + *

+ * There are four allowlists: + *

    + *
  1. + * One for cases where the system permission policy allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM} flag. Can only be + * accessed by pre-installed holders of a dedicated permission. + *
  2. + * One for cases where the system allowlists the permission when upgrading from an OS version in + * which the permission was not restricted to an OS version in which the permission is + * restricted. This list corresponds to the + * {@link PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be accessed by + * pre-installed holders of a dedicated permission or the installer on record. + *
  3. + * One for cases where the installer of the package allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be + * accessed by pre-installed holders of a dedicated permission or the installer on record. + *
  4. + * One for cases where the system exempts the permission when granting a role. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be + * accessed by pre-installed holders of a dedicated permission. + *
+ * + * @param packageName the app for which to get allowlisted permissions + * @param allowlistFlag the flag to determine which allowlist to query. Only one flag can be + * passed. + * @return the allowlisted permissions that are on any of the allowlists you query for + * @throws SecurityException if you try to access a allowlist that you have no access to + * + * @see #addAllowlistedRestrictedPermission(String, String, int) + * @see #removeAllowlistedRestrictedPermission(String, String, int) + * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM + * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE + * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER + * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE + * + * @hide Pending API + */ + @NonNull + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public Set getAllowlistedRestrictedPermissions(@NonNull String packageName, + @PackageManager.PermissionWhitelistFlags int allowlistFlag) { + try { + final List allowlist = mPermissionManager.getWhitelistedRestrictedPermissions( + packageName, allowlistFlag, mContext.getUserId()); + if (allowlist == null) { + return Collections.emptySet(); + } + return new ArraySet<>(allowlist); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Adds a allowlisted restricted permission for an app. + *

+ * Permissions can be hard restricted which means that the app cannot hold them or soft + * restricted where the app can hold the permission but in a weaker form. Whether a permission + * is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard restricted} or + * {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} depends on the permission + * declaration. Allowlisting a hard restricted permission allows for the to hold that permission + * and allowlisting a soft restricted permission allows the app to hold the permission in its + * full, unrestricted form. + *

There are four allowlists: + *

    + *
  1. + * One for cases where the system permission policy allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM} flag. Can only be + * accessed by pre-installed holders of a dedicated permission. + *
  2. + * One for cases where the system allowlists the permission when upgrading from an OS version in + * which the permission was not restricted to an OS version in which the permission is + * restricted. This list corresponds to the + * {@link PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be accessed by + * pre-installed holders of a dedicated permission or the installer on record. + *
  3. + * One for cases where the installer of the package allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be + * accessed by pre-installed holders of a dedicated permission or the installer on record. + *
  4. + * One for cases where the system exempts the permission when granting a role. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be + * accessed by pre-installed holders of a dedicated permission. + *
+ *

+ * You need to specify the allowlists for which to set the allowlisted permissions which will + * clear the previous allowlisted permissions and replace them with the provided ones. + * + * @param packageName the app for which to get allowlisted permissions + * @param permissionName the allowlisted permission to add + * @param allowlistFlags the allowlists to which to add. Passing multiple flags updates all + * specified allowlists. + * @return whether the permission was added to the allowlist + * @throws SecurityException if you try to modify a allowlist that you have no access to. + * + * @see #getAllowlistedRestrictedPermissions(String, int) + * @see #removeAllowlistedRestrictedPermission(String, String, int) + * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM + * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE + * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER + * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public boolean addAllowlistedRestrictedPermission(@NonNull String packageName, + @NonNull String permissionName, + @PackageManager.PermissionWhitelistFlags int allowlistFlags) { + try { + return mPermissionManager.addWhitelistedRestrictedPermission(packageName, + permissionName, allowlistFlags, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Removes a allowlisted restricted permission for an app. + *

+ * Permissions can be hard restricted which means that the app cannot hold them or soft + * restricted where the app can hold the permission but in a weaker form. Whether a permission + * is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard restricted} or + * {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} depends on the permission + * declaration. Allowlisting a hard restricted permission allows for the to hold that permission + * and allowlisting a soft restricted permission allows the app to hold the permission in its + * full, unrestricted form. + *

There are four allowlists: + *

    + *
  1. + * One for cases where the system permission policy allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM} flag. Can only be + * accessed by pre-installed holders of a dedicated permission. + *
  2. + * One for cases where the system allowlists the permission when upgrading from an OS version in + * which the permission was not restricted to an OS version in which the permission is + * restricted. This list corresponds to the + * {@link PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be accessed by + * pre-installed holders of a dedicated permission or the installer on record. + *
  3. + * One for cases where the installer of the package allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be + * accessed by pre-installed holders of a dedicated permission or the installer on record. + *
  4. + * One for cases where the system exempts the permission when granting a role. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be + * accessed by pre-installed holders of a dedicated permission. + *
+ *

+ * You need to specify the allowlists for which to set the allowlisted permissions which will + * clear the previous allowlisted permissions and replace them with the provided ones. + * + * @param packageName the app for which to get allowlisted permissions + * @param permissionName the allowlisted permission to remove + * @param allowlistFlags the allowlists from which to remove. Passing multiple flags updates all + * specified allowlists. + * @return whether the permission was removed from the allowlist + * @throws SecurityException if you try to modify a allowlist that you have no access to. + * + * @see #getAllowlistedRestrictedPermissions(String, int) + * @see #addAllowlistedRestrictedPermission(String, String, int) + * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM + * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE + * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER + * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public boolean removeAllowlistedRestrictedPermission(@NonNull String packageName, + @NonNull String permissionName, + @PackageManager.PermissionWhitelistFlags int allowlistFlags) { + try { + return mPermissionManager.removeWhitelistedRestrictedPermission(packageName, + permissionName, allowlistFlags, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Checks whether an application is exempted from having its permissions be automatically + * revoked when the app is unused for an extended period of time. + *

+ * Only the installer on record that installed the given package, or a holder of + * {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this. + * + * @param packageName the app for which to set exemption + * @return whether the app is exempted + * @throws SecurityException if you you have no access to this + * + * @see #setAutoRevokeExempted + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, + conditional = true) + public boolean isAutoRevokeExempted(@NonNull String packageName) { + try { + return mPermissionManager.isAutoRevokeWhitelisted(packageName, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Marks an application exempted from having its permissions be automatically revoked when the + * app is unused for an extended period of time. + *

+ * Only the installer on record that installed the given package is allowed to call this. + *

+ * Packages start in exempted state, and it is the installer's responsibility to un-exempt the + * packages it installs, unless auto-revoking permissions from that package would cause + * breakages beyond having to re-request the permission(s). + * + * @param packageName the app for which to set exemption + * @param exempted whether the app should be exempted + * @return whether any change took effect + * @throws SecurityException if you you have no access to modify this + * + * @see #isAutoRevokeExempted + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, + conditional = true) + public boolean setAutoRevokeExempted(@NonNull String packageName, boolean exempted) { + try { + return mPermissionManager.setAutoRevokeWhitelisted(packageName, exempted, + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get whether you should show UI with rationale for requesting a permission. You should do this + * only if you do not have the permission and the context in which the permission is requested + * does not clearly communicate to the user what would be the benefit from grating this + * permission. + * + * @param permissionName a permission your app wants to request + * @return whether you can show permission rationale UI + * + * @hide + */ + //@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public boolean shouldShowRequestPermissionRationale(@NonNull String permissionName) { + try { + final String packageName = mContext.getPackageName(); + return mPermissionManager.shouldShowRequestPermissionRationale(permissionName, + packageName, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Add a listener for permission changes for installed packages. + * + * @param listener the listener to add + * + * @hide + */ + //@SystemApi + @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) + public void addOnPermissionsChangeListener( + @NonNull PackageManager.OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + if (mPermissionListeners.get(listener) != null) { + return; + } + final OnPermissionsChangeListenerDelegate delegate = + new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper()); + try { + mPermissionManager.addOnPermissionsChangeListener(delegate); + mPermissionListeners.put(listener, delegate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Remove a listener for permission changes for installed packages. + * + * @param listener the listener to remove + * + * @hide + */ + //@SystemApi + @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) + public void removeOnPermissionsChangeListener( + @NonNull PackageManager.OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + final IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener); + if (delegate != null) { + try { + mPermissionManager.removeOnPermissionsChangeListener(delegate); + mPermissionListeners.remove(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + /** * Gets the version of the runtime permission database. * @@ -174,7 +844,7 @@ public final class PermissionManager { try { parcelableList = ActivityThread.getPermissionManager().getSplitPermissions(); } catch (RemoteException e) { - Slog.e(TAG, "Error getting split permissions", e); + Slog.e(LOG_TAG, "Error getting split permissions", e); return Collections.emptyList(); } @@ -403,10 +1073,11 @@ public final class PermissionManager { // permission this is. final int appId = UserHandle.getAppId(uid); if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { - Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission); + Slog.w(LOG_TAG, "Missing ActivityManager; assuming " + uid + " holds " + + permission); return PackageManager.PERMISSION_GRANTED; } - Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold " + Slog.w(LOG_TAG, "Missing ActivityManager; assuming " + uid + " does not hold " + permission); return PackageManager.PERMISSION_DENIED; } @@ -586,4 +1257,35 @@ public final class PermissionManager { sPackageNamePermissionCache.disableLocal(); } + private final class OnPermissionsChangeListenerDelegate + extends IOnPermissionsChangeListener.Stub implements Handler.Callback{ + private static final int MSG_PERMISSIONS_CHANGED = 1; + + private final PackageManager.OnPermissionsChangedListener mListener; + private final Handler mHandler; + + public OnPermissionsChangeListenerDelegate( + PackageManager.OnPermissionsChangedListener listener, Looper looper) { + mListener = listener; + mHandler = new Handler(looper, this); + } + + @Override + public void onPermissionsChanged(int uid) { + mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget(); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_PERMISSIONS_CHANGED: { + final int uid = msg.arg1; + mListener.onPermissionsChanged(uid); + return true; + } + default: + return false; + } + } + } } diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java index 95da532045acc..4b0ed65e5fde9 100644 --- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java +++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java @@ -90,7 +90,7 @@ public class ApplicationPackageManagerTest extends TestCase { private boolean mAllow3rdPartyOnInternal = true; public MockedApplicationPackageManager() { - super(null, null, null); + super(null, null); } public void setForceAllowOnExternal(boolean forceAllowOnExternal) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 708e050f8a8c6..1dbf8396bcfbe 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -66,7 +66,6 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; -import android.app.ApplicationPackageManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.role.RoleManager; @@ -795,8 +794,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void updatePermissionFlagsInternal(String permName, String packageName, int flagMask, int flagValues, int callingUid, int userId, boolean overridePolicy, PermissionCallback callback) { - if (ApplicationPackageManager.DEBUG_TRACE_PERMISSION_UPDATES - && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) { + if (PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES + && PermissionManager.shouldTraceGrant(packageName, permName, userId)) { Log.i(TAG, "System is updating flags for " + packageName + " " + permName + " for user " + userId + " " + DebugUtils.flagsToString( @@ -1456,8 +1455,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // TODO swap permission name and package name private void grantRuntimePermissionInternal(String permName, String packageName, boolean overridePolicy, int callingUid, final int userId, PermissionCallback callback) { - if (ApplicationPackageManager.DEBUG_TRACE_GRANTS - && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) { + if (PermissionManager.DEBUG_TRACE_GRANTS + && PermissionManager.shouldTraceGrant(packageName, permName, userId)) { Log.i(TAG, "System is granting " + packageName + " " + permName + " for user " + userId + " on behalf of uid " + callingUid + " " + mPackageManagerInt.getNameForUid(callingUid), @@ -1633,8 +1632,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void revokeRuntimePermissionInternal(String permName, String packageName, boolean overridePolicy, int callingUid, final int userId, String reason, PermissionCallback callback) { - if (ApplicationPackageManager.DEBUG_TRACE_PERMISSION_UPDATES - && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) { + if (PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES + && PermissionManager.shouldTraceGrant(packageName, permName, userId)) { Log.i(TAG, "System is revoking " + packageName + " " + permName + " for user " + userId + " on behalf of uid " + callingUid + " " + mPackageManagerInt.getNameForUid(callingUid),