summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/app/AppOpsManager.java9
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PermissionInfo.java10
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java68
-rw-r--r--tests/VoiceInteraction/AndroidManifest.xml2
8 files changed, 96 insertions, 4 deletions
diff --git a/api/current.txt b/api/current.txt
index e736d78..1263186 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 990ea85..caadecb 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 5e55ba7..4b339a1 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 5a63e5f..af574db 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -69,6 +69,13 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
public static final int PROTECTION_FLAG_DEVELOPMENT = 0x20;
/**
+ * Additional flag for {@link #protectionLevel}, corresponding
+ * to the <code>development</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ */
+ public static final int PROTECTION_FLAG_APPOP = 0x40;
+
+ /**
* Mask for {@link #protectionLevel}: the basic protection type.
*/
public static final int PROTECTION_MASK_BASE = 0xf;
@@ -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 a2afb44..7f97726 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2461,7 +2461,7 @@
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
android:label="@string/permlab_pkgUsageStats"
android:description="@string/permdesc_pkgUsageStats"
- android:protectionLevel="signature|system" />
+ android:protectionLevel="signature|system|development|appop" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<!-- @SystemApi Allows an application to collect battery statistics -->
@@ -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" />
<!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 3026514..7311a60 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -212,6 +212,9 @@
<!-- Additional flag from base permission type: this permission can also
(optionally) be granted to development applications. -->
<flag name="development" value="0x20" />
+ <!-- Additional flag from base permission type: this permission is closely
+ associated with an app op for controlling access. -->
+ <flag name="appop" value="0x40" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6de8a8b..69f2f32 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<PackageVerificationState> mPendingVerification
= new SparseArray<PackageVerificationState>();
+ /** Set of packages associated with each app op permission. */
+ final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>();
+
final PackageInstallerService mInstallerService;
HashSet<PackageParser.Package> mDeferredDexOpt = null;
@@ -2917,6 +2920,17 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public String[] getAppOpPermissionPackages(String permissionName) {
+ synchronized (mPackages) {
+ ArraySet<String> 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) {
if (!sUserManager.exists(userId)) return null;
@@ -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<String> 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<N; i++) {
+ String perm = pkg.requestedPermissions.get(i);
+ BasePermission bp = mSettings.mPermissions.get(perm);
+ if (bp != null && (bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
+ ArraySet<String> 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<String> 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<mAppOpPermissionPackages.size(); iperm++) {
+ if (iperm == 0) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("AppOp Permissions:");
+ }
+ pw.print(" AppOp Permission ");
+ pw.print(mAppOpPermissionPackages.keyAt(iperm));
+ pw.println(":");
+ ArraySet<String> pkgs = mAppOpPermissionPackages.valueAt(iperm);
+ for (int ipkg=0; ipkg<pkgs.size(); ipkg++) {
+ pw.print(" "); pw.println(pkgs.valueAt(ipkg));
+ }
+ }
+ }
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index 33f000d..c328b3c 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -1,6 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.voiceinteraction">
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+
<application>
<activity android:name="VoiceInteractionMain" android:label="Voice Interaction"
android:theme="@android:style/Theme.Material">