Loading core/java/android/app/ActivityManager.java +12 −8 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.permission.PermissionManager; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Singleton; Loading Loading @@ -3738,6 +3739,7 @@ public class ActivityManager { } // Isolated processes don't get any permissions. if (UserHandle.isIsolated(uid)) { PermissionManager.addPermissionDenialHint("uid " + uid + " is isolated"); return PackageManager.PERMISSION_DENIED; } // If there is a uid that owns whatever is being accessed, it has Loading @@ -3753,24 +3755,26 @@ public class ActivityManager { Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid, here); */ PermissionManager.addPermissionDenialHint( "Target is not exported. owningUid=" + owningUid); return PackageManager.PERMISSION_DENIED; } if (permission == null) { return PackageManager.PERMISSION_GRANTED; } try { return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return checkUidPermission(permission, uid); } /** @hide */ public static int checkUidPermission(String permission, int uid) { try { List<String> hints = PermissionManager.getPermissionDenialHints(); if (hints == null) { return AppGlobals.getPackageManager().checkUidPermission(permission, uid); } else { return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); .checkUidPermissionWithDenialHintForwarding(permission, uid, hints); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading core/java/android/app/ContextImpl.java +45 −19 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.permission.PermissionManager; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; Loading Loading @@ -98,6 +99,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; Loading Loading @@ -1828,11 +1830,17 @@ class ContextImpl extends Context { } Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold " + permission); PermissionManager.addPermissionDenialHint("Missing ActivityManager"); return PackageManager.PERMISSION_DENIED; } try { List<String> hints = PermissionManager.getPermissionDenialHints(); if (hints == null) { return am.checkPermission(permission, pid, uid); } else { return am.checkPermissionWithDenialHintForwarding(permission, pid, uid, hints); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -1889,43 +1897,61 @@ class ContextImpl extends Context { String permission, int resultOfCheck, boolean selfToo, int uid, String message) { if (resultOfCheck != PackageManager.PERMISSION_GRANTED) { List<String> hints = PermissionManager.getPermissionDenialHints(); throw new SecurityException( (message != null ? (message + ": ") : "") + (selfToo ? "Neither user " + uid + " nor current process has " : "uid " + uid + " does not have ") + permission + "."); : "uid " + uid + " does not have ") + permission + "." + (hints == null ? "" : " Hints: " + hints)); } } @Override public void enforcePermission( String permission, int pid, int uid, String message) { List<String> prev = PermissionManager.collectPermissionDenialHints(this, uid); try { enforce(permission, checkPermission(permission, pid, uid), false, uid, message); } finally { PermissionManager.resetPermissionDenialHints(prev); } } @Override public void enforceCallingPermission(String permission, String message) { List<String> prev = PermissionManager.collectPermissionDenialHints(this, Binder.getCallingUid()); try { enforce(permission, checkCallingPermission(permission), false, Binder.getCallingUid(), message); } finally { PermissionManager.resetPermissionDenialHints(prev); } } @Override public void enforceCallingOrSelfPermission( String permission, String message) { List<String> prev = PermissionManager.collectPermissionDenialHints(this, Binder.getCallingUid()); try { enforce(permission, checkCallingOrSelfPermission(permission), true, Binder.getCallingUid(), message); } finally { PermissionManager.resetPermissionDenialHints(prev); } } @Override Loading core/java/android/app/IActivityManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ interface IActivityManager { int getProcessLimit(); @UnsupportedAppUsage int checkPermission(in String permission, int pid, int uid); int checkPermissionWithDenialHintForwarding(in String permission, int pid, int uid, inout List<String> permissionDenialHints); int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId, in IBinder callerToken); void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri, Loading core/java/android/content/pm/IPackageManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ interface IPackageManager { @UnsupportedAppUsage int checkPermission(String permName, String pkgName, int userId); int checkUidPermissionWithDenialHintForwarding(String permName, int uid, inout List<String> permissionDenialHints); int checkUidPermission(String permName, int uid); @UnsupportedAppUsage Loading core/java/android/permission/PermissionManager.java +122 −0 Original line number Diff line number Diff line Loading @@ -19,15 +19,22 @@ package android.permission; import android.Manifest; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.ContentResolver; import android.content.Context; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.os.Build; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.Immutable; import com.android.internal.util.ArrayUtils; import com.android.server.SystemConfig; import java.util.ArrayList; Loading @@ -42,6 +49,8 @@ import java.util.Objects; @SystemApi @SystemService(Context.PERMISSION_SERVICE) public final class PermissionManager { private static final String LOG_TAG = PermissionManager.class.getSimpleName(); /** * {@link android.content.pm.PackageParser} needs access without having a {@link Context}. * Loading @@ -54,6 +63,119 @@ public final class PermissionManager { private final IPackageManager mPackageManager; /** Permission denials added via {@link addPermissionDenial} */ private static final ThreadLocal<List<String>> sPermissionDenialHints = new ThreadLocal<>(); /** * Report a hint that might explain why a permission check returned * {@link PackageManager#PERMISSION_DENIED}. * * <p>Hints are only collected if enabled via {@link collectPermissionDenialHints} or * when a non-null value was passed to {@link resetPermissionDenialHints} * * @param hint A description of the reason * * @hide */ public static void addPermissionDenialHint(@NonNull String hint) { List<String> hints = sPermissionDenialHints.get(); if (hints == null) { return; } hints.add(hint); } /** * @return hints added via {@link #addPermissionDenialHint(String)} on this thread before. * * @hide */ public static @Nullable List<String> getPermissionDenialHints() { if (Build.IS_USER) { return null; } return sPermissionDenialHints.get(); } /** * Reset the permission denial hints for this thread. * * @param initial The initial values. If not null, enabled collection on this thread. * * @return the previously collected hints * * @hide */ public static @Nullable List<String> resetPermissionDenialHints( @Nullable List<String> initial) { List<String> prev = getPermissionDenialHints(); if (initial == null) { sPermissionDenialHints.remove(); } else { sPermissionDenialHints.set(initial); } return prev; } /** * Enable permission denial hint collection if package is in * {@link Settings.Secure.DEBUG_PACKAGE_PERMISSION_CHECK} * * @param context A context to use * @param uid The uid the permission check is for. * * @return the previously collected hints * * @hide */ public static @Nullable List<String> collectPermissionDenialHints(@NonNull Context context, int uid) { List<String> prev = getPermissionDenialHints(); if (Build.IS_USER) { return prev; } ContentResolver cr = context.getContentResolver(); if (cr == null) { return prev; } String debugSetting; try { debugSetting = Settings.Secure.getString(cr, Settings.Secure.DEBUG_PACKAGE_PERMISSION_CHECK); } catch (IllegalStateException e) { Log.e(LOG_TAG, "Cannot access settings", e); return prev; } if (debugSetting == null) { return prev; } String[] debugPkgs = debugSetting.split(","); PackageManager pm = context.getPackageManager(); if (pm == null) { return prev; } String[] packages = pm.getPackagesForUid(uid); if (packages == null) { return prev; } for (String pkg : packages) { if (ArrayUtils.contains(debugPkgs, pkg)) { sPermissionDenialHints.set(new ArrayList<>(0)); break; } } return prev; } /** * Creates a new instance. * Loading Loading
core/java/android/app/ActivityManager.java +12 −8 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.permission.PermissionManager; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Singleton; Loading Loading @@ -3738,6 +3739,7 @@ public class ActivityManager { } // Isolated processes don't get any permissions. if (UserHandle.isIsolated(uid)) { PermissionManager.addPermissionDenialHint("uid " + uid + " is isolated"); return PackageManager.PERMISSION_DENIED; } // If there is a uid that owns whatever is being accessed, it has Loading @@ -3753,24 +3755,26 @@ public class ActivityManager { Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid, here); */ PermissionManager.addPermissionDenialHint( "Target is not exported. owningUid=" + owningUid); return PackageManager.PERMISSION_DENIED; } if (permission == null) { return PackageManager.PERMISSION_GRANTED; } try { return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return checkUidPermission(permission, uid); } /** @hide */ public static int checkUidPermission(String permission, int uid) { try { List<String> hints = PermissionManager.getPermissionDenialHints(); if (hints == null) { return AppGlobals.getPackageManager().checkUidPermission(permission, uid); } else { return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); .checkUidPermissionWithDenialHintForwarding(permission, uid, hints); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
core/java/android/app/ContextImpl.java +45 −19 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.permission.PermissionManager; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; Loading Loading @@ -98,6 +99,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; Loading Loading @@ -1828,11 +1830,17 @@ class ContextImpl extends Context { } Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold " + permission); PermissionManager.addPermissionDenialHint("Missing ActivityManager"); return PackageManager.PERMISSION_DENIED; } try { List<String> hints = PermissionManager.getPermissionDenialHints(); if (hints == null) { return am.checkPermission(permission, pid, uid); } else { return am.checkPermissionWithDenialHintForwarding(permission, pid, uid, hints); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -1889,43 +1897,61 @@ class ContextImpl extends Context { String permission, int resultOfCheck, boolean selfToo, int uid, String message) { if (resultOfCheck != PackageManager.PERMISSION_GRANTED) { List<String> hints = PermissionManager.getPermissionDenialHints(); throw new SecurityException( (message != null ? (message + ": ") : "") + (selfToo ? "Neither user " + uid + " nor current process has " : "uid " + uid + " does not have ") + permission + "."); : "uid " + uid + " does not have ") + permission + "." + (hints == null ? "" : " Hints: " + hints)); } } @Override public void enforcePermission( String permission, int pid, int uid, String message) { List<String> prev = PermissionManager.collectPermissionDenialHints(this, uid); try { enforce(permission, checkPermission(permission, pid, uid), false, uid, message); } finally { PermissionManager.resetPermissionDenialHints(prev); } } @Override public void enforceCallingPermission(String permission, String message) { List<String> prev = PermissionManager.collectPermissionDenialHints(this, Binder.getCallingUid()); try { enforce(permission, checkCallingPermission(permission), false, Binder.getCallingUid(), message); } finally { PermissionManager.resetPermissionDenialHints(prev); } } @Override public void enforceCallingOrSelfPermission( String permission, String message) { List<String> prev = PermissionManager.collectPermissionDenialHints(this, Binder.getCallingUid()); try { enforce(permission, checkCallingOrSelfPermission(permission), true, Binder.getCallingUid(), message); } finally { PermissionManager.resetPermissionDenialHints(prev); } } @Override Loading
core/java/android/app/IActivityManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ interface IActivityManager { int getProcessLimit(); @UnsupportedAppUsage int checkPermission(in String permission, int pid, int uid); int checkPermissionWithDenialHintForwarding(in String permission, int pid, int uid, inout List<String> permissionDenialHints); int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId, in IBinder callerToken); void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri, Loading
core/java/android/content/pm/IPackageManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ interface IPackageManager { @UnsupportedAppUsage int checkPermission(String permName, String pkgName, int userId); int checkUidPermissionWithDenialHintForwarding(String permName, int uid, inout List<String> permissionDenialHints); int checkUidPermission(String permName, int uid); @UnsupportedAppUsage Loading
core/java/android/permission/PermissionManager.java +122 −0 Original line number Diff line number Diff line Loading @@ -19,15 +19,22 @@ package android.permission; import android.Manifest; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.ContentResolver; import android.content.Context; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.os.Build; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.Immutable; import com.android.internal.util.ArrayUtils; import com.android.server.SystemConfig; import java.util.ArrayList; Loading @@ -42,6 +49,8 @@ import java.util.Objects; @SystemApi @SystemService(Context.PERMISSION_SERVICE) public final class PermissionManager { private static final String LOG_TAG = PermissionManager.class.getSimpleName(); /** * {@link android.content.pm.PackageParser} needs access without having a {@link Context}. * Loading @@ -54,6 +63,119 @@ public final class PermissionManager { private final IPackageManager mPackageManager; /** Permission denials added via {@link addPermissionDenial} */ private static final ThreadLocal<List<String>> sPermissionDenialHints = new ThreadLocal<>(); /** * Report a hint that might explain why a permission check returned * {@link PackageManager#PERMISSION_DENIED}. * * <p>Hints are only collected if enabled via {@link collectPermissionDenialHints} or * when a non-null value was passed to {@link resetPermissionDenialHints} * * @param hint A description of the reason * * @hide */ public static void addPermissionDenialHint(@NonNull String hint) { List<String> hints = sPermissionDenialHints.get(); if (hints == null) { return; } hints.add(hint); } /** * @return hints added via {@link #addPermissionDenialHint(String)} on this thread before. * * @hide */ public static @Nullable List<String> getPermissionDenialHints() { if (Build.IS_USER) { return null; } return sPermissionDenialHints.get(); } /** * Reset the permission denial hints for this thread. * * @param initial The initial values. If not null, enabled collection on this thread. * * @return the previously collected hints * * @hide */ public static @Nullable List<String> resetPermissionDenialHints( @Nullable List<String> initial) { List<String> prev = getPermissionDenialHints(); if (initial == null) { sPermissionDenialHints.remove(); } else { sPermissionDenialHints.set(initial); } return prev; } /** * Enable permission denial hint collection if package is in * {@link Settings.Secure.DEBUG_PACKAGE_PERMISSION_CHECK} * * @param context A context to use * @param uid The uid the permission check is for. * * @return the previously collected hints * * @hide */ public static @Nullable List<String> collectPermissionDenialHints(@NonNull Context context, int uid) { List<String> prev = getPermissionDenialHints(); if (Build.IS_USER) { return prev; } ContentResolver cr = context.getContentResolver(); if (cr == null) { return prev; } String debugSetting; try { debugSetting = Settings.Secure.getString(cr, Settings.Secure.DEBUG_PACKAGE_PERMISSION_CHECK); } catch (IllegalStateException e) { Log.e(LOG_TAG, "Cannot access settings", e); return prev; } if (debugSetting == null) { return prev; } String[] debugPkgs = debugSetting.split(","); PackageManager pm = context.getPackageManager(); if (pm == null) { return prev; } String[] packages = pm.getPackagesForUid(uid); if (packages == null) { return prev; } for (String pkg : packages) { if (ArrayUtils.contains(debugPkgs, pkg)) { sPermissionDenialHints.set(new ArrayList<>(0)); break; } } return prev; } /** * Creates a new instance. * Loading