diff options
| author | TreeHugger Robot <treehugger-gerrit@google.com> | 2019-05-06 06:21:23 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-05-06 06:21:23 +0000 |
| commit | dd82c4513bba24bae16a22a79bf7fdd240643213 (patch) | |
| tree | d5791bdfe33c779591ed01c28b36fca5dcbdb349 /core/java | |
| parent | ec5586823c9cbb7cee579e53efbcb461b7c63100 (diff) | |
| parent | 3623f3219ea964b1d251527533922a1a85897543 (diff) | |
Merge "Add optional reasons why permissions were denied" into qt-dev
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/ActivityManager.java | 20 | ||||
| -rw-r--r-- | core/java/android/app/ContextImpl.java | 64 | ||||
| -rw-r--r-- | core/java/android/app/IActivityManager.aidl | 1 | ||||
| -rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 1 | ||||
| -rw-r--r-- | core/java/android/permission/PermissionManager.java | 122 | ||||
| -rw-r--r-- | core/java/android/provider/Settings.java | 10 |
6 files changed, 191 insertions, 27 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 17368b789645..a36b167004f8 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -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; @@ -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 @@ -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 { - return AppGlobals.getPackageManager() - .checkUidPermission(permission, uid); + List<String> hints = PermissionManager.getPermissionDenialHints(); + if (hints == null) { + return AppGlobals.getPackageManager().checkUidPermission(permission, uid); + } else { + return AppGlobals.getPackageManager() + .checkUidPermissionWithDenialHintForwarding(permission, uid, hints); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 41a4fba0434c..931e3553c2b6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -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; @@ -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; @@ -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 { - return am.checkPermission(permission, pid, uid); + 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(); } @@ -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) { - enforce(permission, - checkPermission(permission, pid, uid), - false, - uid, - 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) { - enforce(permission, - checkCallingPermission(permission), - false, - Binder.getCallingUid(), - 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) { - enforce(permission, - checkCallingOrSelfPermission(permission), - true, - Binder.getCallingUid(), - message); + List<String> prev = PermissionManager.collectPermissionDenialHints(this, + Binder.getCallingUid()); + try { + enforce(permission, + checkCallingOrSelfPermission(permission), + true, + Binder.getCallingUid(), + message); + } finally { + PermissionManager.resetPermissionDenialHints(prev); + } } @Override diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 48ca71690a1b..f82536f65ddb 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -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, diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 6ab4657d727d..225eec13d6eb 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -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 diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 2a41c2065c46..55bb3fe1817c 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -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; @@ -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}. * @@ -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. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7c5a1fb5f787..dbc62f4a12fa 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5786,6 +5786,16 @@ public final class Settings { public static final String ANDROID_ID = "android_id"; /** + * Comma separated list packages to enable collection of permission denial hints for. + * + * @hide + * + * @see android.permission.PermissionManager#collectPermissionDenialHints(Context, int) + */ + public static final String DEBUG_PACKAGE_PERMISSION_CHECK = + "debug_package_permission_check"; + + /** * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead */ @Deprecated |
