From 65404d6c66a744dbf1e3bdd92396e28cdceb7eef Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Sun, 6 Dec 2020 22:51:23 -0800 Subject: [PATCH] Move permission methods in PackageManager to PermissionManager. A number of permission-related methods were implemented in ApplicationPackageManager by calling the IPermissionManager AIDL interface. However since we are moving permission into module, the AIDL inteface can't be an API and the implementions must be moved. This change moves these methods into PermissionManager, with the javadoc and interface from PackageManager and the implementation from AppliationManager. The javadoc remains mostly the same except for style and typo fixes. The API interface also remains the same except for inclusive language changes since we are defining new one and have a chance to fix them now. We have to lazily get the PermissionManager instance because the context passed in may be null for an instrumentation use case. Bug: 158736025 Test: presubmit Change-Id: I1c28433ca6200679a41e3518354fe03b866621b5 --- core/java/android/app/ActivityThread.java | 3 +- .../app/ApplicationPackageManager.java | 284 ++----- core/java/android/app/ContextImpl.java | 6 +- .../android/content/pm/PackageManager.java | 27 +- .../android/permission/PermissionManager.java | 710 +++++++++++++++++- .../app/ApplicationPackageManagerTest.java | 2 +- .../permission/PermissionManagerService.java | 13 +- 7 files changed, 788 insertions(+), 257 deletions(-) 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 2a529bb7b2e74..6aafbe1039ef1 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; @@ -794,8 +793,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( @@ -1455,8 +1454,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), @@ -1621,8 +1620,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),