diff --git a/api/current.txt b/api/current.txt index e736d78aa24ba..126318655f61f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3820,6 +3820,7 @@ package android.app { method public void startWatchingMode(java.lang.String, java.lang.String, android.app.AppOpsManager.OnOpChangedListener); method public void stopWatchingMode(android.app.AppOpsManager.OnOpChangedListener); field public static final int MODE_ALLOWED = 0; // 0x0 + field public static final int MODE_DEFAULT = 3; // 0x3 field public static final int MODE_ERRORED = 2; // 0x2 field public static final int MODE_IGNORED = 1; // 0x1 field public static final java.lang.String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -8877,6 +8878,7 @@ package android.content.pm { field public static final android.os.Parcelable.Creator CREATOR; field public static final int FLAG_COSTS_MONEY = 1; // 0x1 field public static final int PROTECTION_DANGEROUS = 1; // 0x1 + field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40 field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20 field public static final int PROTECTION_FLAG_SYSTEM = 16; // 0x10 field public static final int PROTECTION_MASK_BASE = 15; // 0xf diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 990ea85f99e1c..caadecb29dc73 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -94,6 +94,13 @@ public class AppOpsManager { */ public static final int MODE_ERRORED = 2; + /** + * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller should + * use its default security check. This mode is not normally used; it should only be used + * with appop permissions, and callers must explicitly check for it and deal with it. + */ + public static final int MODE_DEFAULT = 3; + // when adding one of these: // - increment _NUM_OP // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode @@ -588,7 +595,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, - AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS + AppOpsManager.MODE_DEFAULT, // OP_GET_USAGE_STATS AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 5e55ba72e6a89..4b339a1e1774c 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -110,6 +110,8 @@ interface IPackageManager { int getFlagsForUid(int uid); + String[] getAppOpPermissionPackages(String permissionName); + ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId); boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId); diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index 5a63e5f656f53..af574dbeb80c5 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -68,6 +68,13 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { */ public static final int PROTECTION_FLAG_DEVELOPMENT = 0x20; + /** + * Additional flag for {@link #protectionLevel}, corresponding + * to the development value of + * {@link android.R.attr#protectionLevel}. + */ + public static final int PROTECTION_FLAG_APPOP = 0x40; + /** * Mask for {@link #protectionLevel}: the basic protection type. */ @@ -153,6 +160,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { if ((level&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) { protLevel += "|development"; } + if ((level&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) { + protLevel += "|appop"; + } return protLevel; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a2afb44fae94b..7f97726a6ff21 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2461,7 +2461,7 @@ + android:protectionLevel="signature|system|development|appop" /> @@ -2469,7 +2469,7 @@ android:permissionGroup="android.permission-group.SYSTEM_TOOLS" android:label="@string/permlab_batteryStats" android:description="@string/permdesc_batteryStats" - android:protectionLevel="signature|system" /> + android:protectionLevel="signature|system|development" /> + + diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6de8a8b77187b..69f2f32ac7c0b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -474,6 +474,9 @@ public class PackageManagerService extends IPackageManager.Stub { final SparseArray mPendingVerification = new SparseArray(); + /** Set of packages associated with each app op permission. */ + final ArrayMap> mAppOpPermissionPackages = new ArrayMap<>(); + final PackageInstallerService mInstallerService; HashSet mDeferredDexOpt = null; @@ -2916,6 +2919,17 @@ public class PackageManagerService extends IPackageManager.Stub { return 0; } + @Override + public String[] getAppOpPermissionPackages(String permissionName) { + synchronized (mPackages) { + ArraySet pkgs = mAppOpPermissionPackages.get(permissionName); + if (pkgs == null) { + return null; + } + return pkgs.toArray(new String[pkgs.size()]); + } + } + @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { @@ -6591,6 +6605,31 @@ public class PackageManagerService extends IPackageManager.Stub { r.append(p.info.name); } } + if ((p.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) { + ArraySet appOpPerms = mAppOpPermissionPackages.get(p.info.name); + if (appOpPerms != null) { + appOpPerms.remove(pkg.packageName); + } + } + } + if (r != null) { + if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); + } + + N = pkg.requestedPermissions.size(); + r = null; + for (i=0; i appOpPerms = mAppOpPermissionPackages.get(perm); + if (appOpPerms != null) { + appOpPerms.remove(pkg.packageName); + if (appOpPerms.isEmpty()) { + mAppOpPermissionPackages.remove(perm); + } + } + } } if (r != null) { if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); @@ -6775,6 +6814,15 @@ public class PackageManagerService extends IPackageManager.Stub { final String perm = bp.name; boolean allowed; boolean allowedSig = false; + if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) { + // Keep track of app op permissions. + ArraySet pkgs = mAppOpPermissionPackages.get(bp.name); + if (pkgs == null) { + pkgs = new ArraySet<>(); + mAppOpPermissionPackages.put(bp.name, pkgs); + } + pkgs.add(pkg.packageName); + } final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; if (level == PermissionInfo.PROTECTION_NORMAL || level == PermissionInfo.PROTECTION_DANGEROUS) { @@ -6837,7 +6885,9 @@ public class PackageManagerService extends IPackageManager.Stub { + " (protectionLevel=" + bp.protectionLevel + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + ")"); - } else { + } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) { + // Don't print warning for app op permissions, since it is fine for them + // not to be granted, there is a UI for the user to decide. Slog.w(TAG, "Not granting permission " + perm + " to package " + pkg.packageName + " (protectionLevel=" + bp.protectionLevel @@ -12426,6 +12476,22 @@ public class PackageManagerService extends IPackageManager.Stub { if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { mSettings.dumpPermissionsLPr(pw, packageName, dumpState); + if (packageName == null) { + for (int iperm=0; iperm pkgs = mAppOpPermissionPackages.valueAt(iperm); + for (int ipkg=0; ipkg + +