Skip to content

Commit e639da7

Browse files
author
Dianne Hackborn
committed
New development permissions.
These are permissions that an application can request, but won't normally be granted. To have the permission granted, the user must explicitly do so through a new "adb shell pm grant" command. I put these permissions in the "development tools" permission group. Looking at the stuff there, I think all of the permissions we already had in that group should be turned to development permissions; I don't think any of them are protecting public APIs, and they are really not things normal applications should use. The support this, the protectionLevel of a permission has been modified to consist of a base protection type with additional flags. The signatureOrSystem permission has thus been converted to a signature base type with a new "system" flag; you can use "system" and/or "dangerous" flags with signature permissions as desired. The permissions UI has been updated to understand these new types of permissions and know when to display them. Along with doing that, it also now shows you which permissions are new when updating an existing application. This also starts laying the ground-work for "optional" permissions (which development permissions are a certain specialized form of). Completing that work requires some more features in the package manager to understand generic optional permissions (having a facility to not apply them when installing), along with the appropriate UI for the app and user to manage those permissions. Change-Id: I6571785c6bb5f6b291862b7a9be584885f88f3a5
1 parent b8678d7 commit e639da7

File tree

17 files changed

+691
-200
lines changed

17 files changed

+691
-200
lines changed

api/current.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6181,6 +6181,8 @@ package android.content.pm {
61816181
method public int describeContents();
61826182
method public void writeToParcel(android.os.Parcel, int);
61836183
field public static final android.os.Parcelable.Creator CREATOR;
6184+
field public static final int REQUESTED_PERMISSION_GRANTED = 2; // 0x2
6185+
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
61846186
field public android.content.pm.ActivityInfo[] activities;
61856187
field public android.content.pm.ApplicationInfo applicationInfo;
61866188
field public android.content.pm.ConfigurationInfo[] configPreferences;
@@ -6194,6 +6196,7 @@ package android.content.pm {
61946196
field public android.content.pm.ActivityInfo[] receivers;
61956197
field public android.content.pm.FeatureInfo[] reqFeatures;
61966198
field public java.lang.String[] requestedPermissions;
6199+
field public int[] requestedPermissionsFlags;
61976200
field public android.content.pm.ServiceInfo[] services;
61986201
field public java.lang.String sharedUserId;
61996202
field public int sharedUserLabel;
@@ -6416,6 +6419,10 @@ package android.content.pm {
64166419
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
64176420
field public static final android.os.Parcelable.Creator CREATOR;
64186421
field public static final int PROTECTION_DANGEROUS = 1; // 0x1
6422+
field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20
6423+
field public static final int PROTECTION_FLAG_SYSTEM = 16; // 0x10
6424+
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
6425+
field public static final int PROTECTION_MASK_FLAGS = 240; // 0xf0
64196426
field public static final int PROTECTION_NORMAL = 0; // 0x0
64206427
field public static final int PROTECTION_SIGNATURE = 2; // 0x2
64216428
field public static final int PROTECTION_SIGNATURE_OR_SYSTEM = 3; // 0x3

cmds/pm/src/com/android/commands/pm/Pm.java

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ public void run(String[] args) {
126126
return;
127127
}
128128

129+
if ("grant".equals(op)) {
130+
runGrantRevokePermission(true);
131+
return;
132+
}
133+
134+
if ("revoke".equals(op)) {
135+
runGrantRevokePermission(false);
136+
return;
137+
}
138+
129139
if ("set-install-location".equals(op)) {
130140
runSetInstallLocation();
131141
return;
@@ -596,8 +606,9 @@ private void doListPermissions(ArrayList<String> groupList,
596606
if (groups && groupName == null && pi.group != null) {
597607
continue;
598608
}
599-
if (pi.protectionLevel < startProtectionLevel
600-
|| pi.protectionLevel > endProtectionLevel) {
609+
final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
610+
if (base < startProtectionLevel
611+
|| base > endProtectionLevel) {
601612
continue;
602613
}
603614
if (summary) {
@@ -627,22 +638,8 @@ private void doListPermissions(ArrayList<String> groupList,
627638
+ loadText(pi, pi.descriptionRes,
628639
pi.nonLocalizedDescription));
629640
}
630-
String protLevel = "unknown";
631-
switch(pi.protectionLevel) {
632-
case PermissionInfo.PROTECTION_DANGEROUS:
633-
protLevel = "dangerous";
634-
break;
635-
case PermissionInfo.PROTECTION_NORMAL:
636-
protLevel = "normal";
637-
break;
638-
case PermissionInfo.PROTECTION_SIGNATURE:
639-
protLevel = "signature";
640-
break;
641-
case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM:
642-
protLevel = "signatureOrSystem";
643-
break;
644-
}
645-
System.out.println(prefix + " protectionLevel:" + protLevel);
641+
System.out.println(prefix + " protectionLevel:"
642+
+ PermissionInfo.protectionToString(pi.protectionLevel));
646643
}
647644
}
648645
}
@@ -1063,6 +1060,36 @@ private void runSetEnabledSetting(int state) {
10631060
}
10641061
}
10651062

1063+
private void runGrantRevokePermission(boolean grant) {
1064+
String pkg = nextArg();
1065+
if (pkg == null) {
1066+
System.err.println("Error: no package specified");
1067+
showUsage();
1068+
return;
1069+
}
1070+
String perm = nextArg();
1071+
if (perm == null) {
1072+
System.err.println("Error: no permission specified");
1073+
showUsage();
1074+
return;
1075+
}
1076+
try {
1077+
if (grant) {
1078+
mPm.grantPermission(pkg, perm);
1079+
} else {
1080+
mPm.revokePermission(pkg, perm);
1081+
}
1082+
} catch (RemoteException e) {
1083+
System.err.println(e.toString());
1084+
System.err.println(PM_NOT_RUNNING_ERR);
1085+
} catch (IllegalArgumentException e) {
1086+
System.err.println("Bad argument: " + e.toString());
1087+
showUsage();
1088+
} catch (SecurityException e) {
1089+
System.err.println("Operation not allowed: " + e.toString());
1090+
}
1091+
}
1092+
10661093
/**
10671094
* Displays the package file for a package.
10681095
* @param pckg
@@ -1158,6 +1185,8 @@ private static void showUsage() {
11581185
System.err.println(" pm enable PACKAGE_OR_COMPONENT");
11591186
System.err.println(" pm disable PACKAGE_OR_COMPONENT");
11601187
System.err.println(" pm disable-user PACKAGE_OR_COMPONENT");
1188+
System.err.println(" pm grant PACKAGE PERMISSION");
1189+
System.err.println(" pm revoke PACKAGE PERMISSION");
11611190
System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]");
11621191
System.err.println(" pm get-install-location");
11631192
System.err.println(" pm create-profile USER_NAME");
@@ -1208,6 +1237,10 @@ private static void showUsage() {
12081237
System.err.println("pm enable, disable, disable-user: these commands change the enabled state");
12091238
System.err.println(" of a given package or component (written as \"package/class\").");
12101239
System.err.println("");
1240+
System.err.println("pm grant, revoke: these commands either grant or revoke permissions");
1241+
System.err.println(" to applications. Only optional permissions the application has");
1242+
System.err.println(" declared can be granted or revoked.");
1243+
System.err.println("");
12111244
System.err.println("pm get-install-location: returns the current install location.");
12121245
System.err.println(" 0 [auto]: Let system decide the best location");
12131246
System.err.println(" 1 [internal]: Install on internal device storage");

core/java/android/app/ApplicationPackageManager.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,24 @@ public void removePermission(String name) {
331331
}
332332
}
333333

334+
@Override
335+
public void grantPermission(String packageName, String permissionName) {
336+
try {
337+
mPM.grantPermission(packageName, permissionName);
338+
} catch (RemoteException e) {
339+
throw new RuntimeException("Package manager has died", e);
340+
}
341+
}
342+
343+
@Override
344+
public void revokePermission(String packageName, String permissionName) {
345+
try {
346+
mPM.revokePermission(packageName, permissionName);
347+
} catch (RemoteException e) {
348+
throw new RuntimeException("Package manager has died", e);
349+
}
350+
}
351+
334352
@Override
335353
public int checkSignatures(String pkg1, String pkg2) {
336354
try {

core/java/android/content/pm/IPackageManager.aidl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ interface IPackageManager {
8181
boolean addPermission(in PermissionInfo info);
8282

8383
void removePermission(String name);
84-
84+
85+
void grantPermission(String packageName, String permissionName);
86+
87+
void revokePermission(String packageName, String permissionName);
88+
8589
boolean isProtectedBroadcast(String actionName);
8690

8791
int checkSignatures(String pkg1, String pkg2);

core/java/android/content/pm/PackageInfo.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,30 @@ public class PackageInfo implements Parcelable {
140140
*/
141141
public String[] requestedPermissions;
142142

143+
/**
144+
* Array of flags of all {@link android.R.styleable#AndroidManifestUsesPermission
145+
* &lt;uses-permission&gt;} tags included under &lt;manifest&gt;,
146+
* or null if there were none. This is only filled in if the flag
147+
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
148+
* the corresponding entry in {@link #requestedPermissions}, and will have
149+
* the flags {@link #REQUESTED_PERMISSION_REQUIRED} and
150+
* {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
151+
*/
152+
public int[] requestedPermissionsFlags;
153+
154+
/**
155+
* Flag for {@link #requestedPermissionsFlags}: the requested permission
156+
* is required for the application to run; the user can not optionally
157+
* disable it.
158+
*/
159+
public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
160+
161+
/**
162+
* Flag for {@link #requestedPermissionsFlags}: the requested permission
163+
* is currently granted to the application.
164+
*/
165+
public static final int REQUESTED_PERMISSION_GRANTED = 1<<1;
166+
143167
/**
144168
* Array of all signatures read from the package file. This is only filled
145169
* in if the flag {@link PackageManager#GET_SIGNATURES} was set.
@@ -229,6 +253,7 @@ public void writeToParcel(Parcel dest, int parcelableFlags) {
229253
dest.writeTypedArray(instrumentation, parcelableFlags);
230254
dest.writeTypedArray(permissions, parcelableFlags);
231255
dest.writeStringArray(requestedPermissions);
256+
dest.writeIntArray(requestedPermissionsFlags);
232257
dest.writeTypedArray(signatures, parcelableFlags);
233258
dest.writeTypedArray(configPreferences, parcelableFlags);
234259
dest.writeTypedArray(reqFeatures, parcelableFlags);
@@ -266,6 +291,7 @@ private PackageInfo(Parcel source) {
266291
instrumentation = source.createTypedArray(InstrumentationInfo.CREATOR);
267292
permissions = source.createTypedArray(PermissionInfo.CREATOR);
268293
requestedPermissions = source.createStringArray();
294+
requestedPermissionsFlags = source.createIntArray();
269295
signatures = source.createTypedArray(Signature.CREATOR);
270296
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
271297
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);

core/java/android/content/pm/PackageManager.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,29 @@ public abstract ProviderInfo getProviderInfo(ComponentName component,
14741474
*/
14751475
public abstract void removePermission(String name);
14761476

1477+
/**
1478+
* Grant a permission to an application which the application does not
1479+
* already have. The permission must have been requested by the application,
1480+
* but as an optional permission. If the application is not allowed to
1481+
* hold the permission, a SecurityException is thrown.
1482+
* @hide
1483+
*
1484+
* @param packageName The name of the package that the permission will be
1485+
* granted to.
1486+
* @param permissionName The name of the permission.
1487+
*/
1488+
public abstract void grantPermission(String packageName, String permissionName);
1489+
1490+
/**
1491+
* Revoke a permission that was previously granted by {@link #grantPermission}.
1492+
* @hide
1493+
*
1494+
* @param packageName The name of the package that the permission will be
1495+
* granted to.
1496+
* @param permissionName The name of the permission.
1497+
*/
1498+
public abstract void revokePermission(String packageName, String permissionName);
1499+
14771500
/**
14781501
* Compare the signatures of two packages to determine if the same
14791502
* signature appears in both of them. If they do contain the same
@@ -2125,7 +2148,7 @@ public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
21252148
if ((flags & GET_SIGNATURES) != 0) {
21262149
packageParser.collectCertificates(pkg, 0);
21272150
}
2128-
return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0);
2151+
return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null);
21292152
}
21302153

21312154
/**

core/java/android/content/pm/PackageParser.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import java.security.spec.X509EncodedKeySpec;
5252
import java.util.ArrayList;
5353
import java.util.Enumeration;
54+
import java.util.HashSet;
5455
import java.util.Iterator;
5556
import java.util.List;
5657
import java.util.jar.Attributes;
@@ -211,7 +212,8 @@ private static final boolean isPackageFilename(String name) {
211212
* @param flags indicating which optional information is included.
212213
*/
213214
public static PackageInfo generatePackageInfo(PackageParser.Package p,
214-
int gids[], int flags, long firstInstallTime, long lastUpdateTime) {
215+
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
216+
HashSet<String> grantedPermissions) {
215217

216218
final int userId = Binder.getOrigCallingUser();
217219

@@ -346,8 +348,16 @@ public static PackageInfo generatePackageInfo(PackageParser.Package p,
346348
N = p.requestedPermissions.size();
347349
if (N > 0) {
348350
pi.requestedPermissions = new String[N];
351+
pi.requestedPermissionsFlags = new int[N];
349352
for (int i=0; i<N; i++) {
350-
pi.requestedPermissions[i] = p.requestedPermissions.get(i);
353+
final String perm = p.requestedPermissions.get(i);
354+
pi.requestedPermissions[i] = perm;
355+
if (p.requestedPermissionsRequired.get(i)) {
356+
pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
357+
}
358+
if (grantedPermissions != null && grantedPermissions.contains(perm)) {
359+
pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
360+
}
351361
}
352362
}
353363
}
@@ -927,11 +937,14 @@ private Package parsePackage(
927937
// that may change.
928938
String name = sa.getNonResourceString(
929939
com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
940+
boolean required = sa.getBoolean(
941+
com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
930942

931943
sa.recycle();
932944

933945
if (name != null && !pkg.requestedPermissions.contains(name)) {
934946
pkg.requestedPermissions.add(name.intern());
947+
pkg.requestedPermissionsRequired.add(required);
935948
}
936949

937950
XmlUtils.skipCurrentTag(parser);
@@ -1419,12 +1432,24 @@ private Permission parsePermission(Package owner, Resources res,
14191432
PermissionInfo.PROTECTION_NORMAL);
14201433

14211434
sa.recycle();
1422-
1435+
14231436
if (perm.info.protectionLevel == -1) {
14241437
outError[0] = "<permission> does not specify protectionLevel";
14251438
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
14261439
return null;
14271440
}
1441+
1442+
perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
1443+
1444+
if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
1445+
if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
1446+
PermissionInfo.PROTECTION_SIGNATURE) {
1447+
outError[0] = "<permission> protectionLevel specifies a flag but is "
1448+
+ "not based on signature type";
1449+
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1450+
return null;
1451+
}
1452+
}
14281453

14291454
if (!parseAllMetaData(res, parser, attrs, "<permission>", perm,
14301455
outError)) {
@@ -2951,6 +2976,7 @@ public final static class Package {
29512976
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
29522977

29532978
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
2979+
public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
29542980

29552981
public ArrayList<String> protectedBroadcasts;
29562982

0 commit comments

Comments
 (0)