summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2019-05-06 06:21:23 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2019-05-06 06:21:23 +0000
commitdd82c4513bba24bae16a22a79bf7fdd240643213 (patch)
treed5791bdfe33c779591ed01c28b36fca5dcbdb349 /core/java
parentec5586823c9cbb7cee579e53efbcb461b7c63100 (diff)
parent3623f3219ea964b1d251527533922a1a85897543 (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.java20
-rw-r--r--core/java/android/app/ContextImpl.java64
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/permission/PermissionManager.java122
-rw-r--r--core/java/android/provider/Settings.java10
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