summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dianne Hackborn <hackbod@google.com> 2015-06-24 15:19:17 -0700
committer Dianne Hackborn <hackbod@google.com> 2015-06-26 13:28:29 -0700
commitca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6 (patch)
tree12d4d5b3d414d42fb72e9033b286d88a0e0ee952
parentff81025a9def3e56908339ad846bff515d5ecbfb (diff)
Fix issue #22023824: Download folder is not created in internal storage
The media provider and some other things need to be given storage access. Also, seems like we should give storage access to the camera app as well. And add a dump dump command that will dump data about a particular permission name. Change-Id: Idaaa9bba2ff4dc95290cf6d17e5df933df91e909
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java25
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java37
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java43
-rw-r--r--services/core/java/com/android/server/pm/PermissionsState.java18
-rw-r--r--services/core/java/com/android/server/pm/Settings.java98
6 files changed, 184 insertions, 39 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 2be44bcecb26..ce83caadb43e 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -204,6 +204,10 @@ public final class Pm {
return runGrantRevokePermission(false);
}
+ if ("reset-permissions".equals(op)) {
+ return runResetPermissions();
+ }
+
if ("set-permission-enforced".equals(op)) {
return runSetPermissionEnforced();
}
@@ -1636,6 +1640,24 @@ public final class Pm {
}
}
+ private int runResetPermissions() {
+ try {
+ mPm.resetRuntimePermissions();
+ return 0;
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
+ } catch (IllegalArgumentException e) {
+ System.err.println("Bad argument: " + e.toString());
+ showUsage();
+ return 1;
+ } catch (SecurityException e) {
+ System.err.println("Operation not allowed: " + e.toString());
+ return 1;
+ }
+ }
+
private int runSetPermissionEnforced() {
final String permission = nextArg();
if (permission == null) {
@@ -1911,6 +1933,7 @@ public final class Pm {
System.err.println(" pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm grant [--user USER_ID] PACKAGE PERMISSION");
System.err.println(" pm revoke [--user USER_ID] PACKAGE PERMISSION");
+ System.err.println(" pm reset-permissions");
System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]");
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
@@ -1988,6 +2011,8 @@ public final class Pm {
System.err.println(" manifest, be runtime permissions (protection level dangerous),");
System.err.println(" and the app targeting SDK greater than Lollipop MR1.");
System.err.println("");
+ System.err.println("pm reset-permissions: revert all runtime permissions to their default state.");
+ System.err.println("");
System.err.println("pm get-install-location: returns the current install location.");
System.err.println(" 0 [auto]: Let system decide the best location");
System.err.println(" 1 [internal]: Install on internal device storage");
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c9853df80389..cea6e993c250 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -102,6 +102,8 @@ interface IPackageManager {
void revokeRuntimePermission(String packageName, String permissionName, int userId);
+ void resetRuntimePermissions();
+
int getPermissionFlags(String permissionName, String packageName, int userId);
void updatePermissionFlags(String permissionName, String packageName, int flagMask,
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 3ea384c1a05d..b9993b1c0239 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -17,11 +17,13 @@
package com.android.server.pm;
import android.Manifest;
+import android.app.DownloadManager;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal.PackagesProvider;
import android.content.pm.PackageParser;
+import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
@@ -228,6 +230,7 @@ final class DefaultPermissionGrantPolicy {
for (int i = 0; i < installerCount; i++) {
PackageParser.Package installPackage = installerPackages.get(i);
grantInstallPermissionsLPw(installPackage, INSTALLER_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(installPackage, STORAGE_PERMISSIONS, userId);
}
// Verifiers
@@ -239,6 +242,7 @@ final class DefaultPermissionGrantPolicy {
for (int i = 0; i < verifierCount; i++) {
PackageParser.Package verifierPackage = verifierPackages.get(i);
grantInstallPermissionsLPw(verifierPackage, VERIFIER_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(verifierPackage, STORAGE_PERMISSIONS, userId);
}
// SetupWizard
@@ -273,6 +277,30 @@ final class DefaultPermissionGrantPolicy {
&& doesPackageSupportRuntimePermissions(cameraPackage)) {
grantRuntimePermissionsLPw(cameraPackage, CAMERA_PERMISSIONS, userId);
grantRuntimePermissionsLPw(cameraPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(cameraPackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Media provider
+ PackageParser.Package mediaStorePackage = getDefaultProviderAuthorityPackageLPr(
+ MediaStore.AUTHORITY, userId);
+ if (mediaStorePackage != null) {
+ grantRuntimePermissionsLPw(mediaStorePackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Downloads provider
+ PackageParser.Package downloadsPackage = getDefaultProviderAuthorityPackageLPr(
+ "downloads", userId);
+ if (downloadsPackage != null) {
+ grantRuntimePermissionsLPw(downloadsPackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Downloads UI
+ Intent downloadsUiIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
+ PackageParser.Package downloadsUiPackage = getDefaultSystemHandlerActvityPackageLPr(
+ downloadsUiIntent, userId);
+ if (downloadsUiPackage != null
+ && doesPackageSupportRuntimePermissions(downloadsUiPackage)) {
+ grantRuntimePermissionsLPw(downloadsUiPackage, STORAGE_PERMISSIONS, userId);
}
// Messaging
@@ -452,6 +480,15 @@ final class DefaultPermissionGrantPolicy {
return null;
}
+ private PackageParser.Package getDefaultProviderAuthorityPackageLPr(
+ String authority, int userId) {
+ ProviderInfo provider = mService.resolveContentProvider(authority, 0, userId);
+ if (provider != null) {
+ return getSystemPackageLPr(provider.packageName);
+ }
+ return null;
+ }
+
private PackageParser.Package getSystemPackageLPr(String packageName) {
PackageParser.Package pkg = mService.mPackages.get(packageName);
if (pkg != null && pkg.isSystemApp()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 40ff3f42ea97..1fd68b8c8d38 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3340,6 +3340,27 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public void resetRuntimePermissions() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ "revokeRuntimePermission");
+
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "resetRuntimePermissions");
+ }
+
+ synchronized (mPackages) {
+ updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL);
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ mDefaultPermissionPolicy.grantDefaultPermissions(userId);
+ }
+ }
+ }
+
+ @Override
public int getPermissionFlags(String name, String packageName, int userId) {
if (!sUserManager.exists(userId)) {
return 0;
@@ -14190,6 +14211,7 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean checkin = false;
String packageName = null;
+ ArraySet<String> permissionNames = null;
int opti = 0;
while (opti < args.length) {
@@ -14213,6 +14235,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pw.println(" k[eysets]: print known keysets");
pw.println(" r[esolvers]: dump intent resolvers");
pw.println(" perm[issions]: dump permissions");
+ pw.println(" permission [name ...]: dump declaration and use of given permission");
pw.println(" pref[erred]: print preferred package settings");
pw.println(" preferred-xml [--full]: print preferred package settings as xml");
pw.println(" prov[iders]: dump content providers");
@@ -14254,6 +14277,18 @@ public class PackageManagerService extends IPackageManager.Stub {
dumpState.setDump(DumpState.DUMP_RESOLVERS);
} else if ("perm".equals(cmd) || "permissions".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PERMISSIONS);
+ } else if ("permission".equals(cmd)) {
+ if (opti >= args.length) {
+ pw.println("Error: permission requires permission name");
+ return;
+ }
+ permissionNames = new ArraySet<>();
+ while (opti < args.length) {
+ permissionNames.add(args[opti]);
+ opti++;
+ }
+ dumpState.setDump(DumpState.DUMP_PERMISSIONS
+ | DumpState.DUMP_PACKAGES | DumpState.DUMP_SHARED_USERS);
} else if ("pref".equals(cmd) || "preferred".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PREFERRED);
} else if ("preferred-xml".equals(cmd)) {
@@ -14536,8 +14571,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
- mSettings.dumpPermissionsLPr(pw, packageName, dumpState);
- if (packageName == null) {
+ mSettings.dumpPermissionsLPr(pw, packageName, permissionNames, dumpState);
+ if (packageName == null && permissionNames == null) {
for (int iperm=0; iperm<mAppOpPermissionPackages.size(); iperm++) {
if (iperm == 0) {
if (dumpState.onTitlePrinted())
@@ -14597,11 +14632,11 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
- mSettings.dumpPackagesLPr(pw, packageName, dumpState, checkin);
+ mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin);
}
if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
- mSettings.dumpSharedUsersLPr(pw, packageName, dumpState, checkin);
+ mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) {
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index 04beafd0da45..57ef284f2758 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -219,6 +219,22 @@ public final class PermissionsState {
}
/**
+ * Returns whether the state has any known request for the given permission name,
+ * whether or not it has been granted.
+ */
+ public boolean hasRequestedPermission(ArraySet<String> names) {
+ if (mPermissions == null) {
+ return false;
+ }
+ for (int i=names.size()-1; i>=0; i--) {
+ if (mPermissions.get(names.valueAt(i)) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Gets all permissions for a given device user id regardless if they
* are install time or runtime permissions.
*
@@ -446,7 +462,7 @@ public final class PermissionsState {
}
}
- return permissionStates;
+ return permissionStates;
}
private int grantPermission(BasePermission permission, int userId) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index dcd7799d7821..c54774927823 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3881,8 +3881,9 @@ final class Settings {
ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
- void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, PackageSetting ps,
- SimpleDateFormat sdf, Date date, List<UserInfo> users) {
+ void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
+ ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
+ Date date, List<UserInfo> users) {
if (checkinTag != null) {
pw.print(checkinTag);
pw.print(",");
@@ -3953,10 +3954,13 @@ final class Settings {
}
pw.print(prefix); pw.print(" pkg="); pw.println(ps.pkg);
pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString);
- pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
- pw.print(prefix); pw.print(" legacyNativeLibraryDir="); pw.println(ps.legacyNativeLibraryPathString);
- pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
- pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
+ if (permissionNames == null) {
+ pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ pw.print(prefix); pw.print(" legacyNativeLibraryDir=");
+ pw.println(ps.legacyNativeLibraryPathString);
+ pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
+ pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
+ }
pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
if (ps.pkg != null) {
pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
@@ -3969,8 +3973,10 @@ final class Settings {
pw.println(ps.pkg.applicationInfo.toString());
pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
FLAG_DUMP_SPEC); pw.println();
- pw.print(prefix); pw.print(" priavateFlags="); printFlags(pw,
- ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
+ if (ps.pkg.applicationInfo.privateFlags != 0) {
+ pw.print(prefix); pw.print(" privateFlags="); printFlags(pw,
+ ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
+ }
pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
pw.print(prefix); pw.print(" supportsScreens=[");
boolean first = true;
@@ -4063,9 +4069,9 @@ final class Settings {
pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
pw.println();
- if (ps.sharedUser == null) {
+ if (ps.sharedUser == null || permissionNames != null) {
PermissionsState permissionsState = ps.getPermissionsState();
- dumpInstallPermissionsLPr(pw, prefix + " ", permissionsState);
+ dumpInstallPermissionsLPr(pw, prefix + " ", permissionNames, permissionsState);
}
for (UserInfo user : users) {
@@ -4089,28 +4095,31 @@ final class Settings {
if (ps.sharedUser == null) {
PermissionsState permissionsState = ps.getPermissionsState();
dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id));
- dumpRuntimePermissionsLPr(pw, prefix + " ", permissionsState
+ dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissionsState
.getRuntimePermissionStates(user.id));
}
- ArraySet<String> cmp = ps.getDisabledComponents(user.id);
- if (cmp != null && cmp.size() > 0) {
- pw.print(prefix); pw.println(" disabledComponents:");
- for (String s : cmp) {
- pw.print(prefix); pw.print(" "); pw.println(s);
+ if (permissionNames == null) {
+ ArraySet<String> cmp = ps.getDisabledComponents(user.id);
+ if (cmp != null && cmp.size() > 0) {
+ pw.print(prefix); pw.println(" disabledComponents:");
+ for (String s : cmp) {
+ pw.print(prefix); pw.print(" "); pw.println(s);
+ }
}
- }
- cmp = ps.getEnabledComponents(user.id);
- if (cmp != null && cmp.size() > 0) {
- pw.print(prefix); pw.println(" enabledComponents:");
- for (String s : cmp) {
- pw.print(prefix); pw.print(" "); pw.println(s);
+ cmp = ps.getEnabledComponents(user.id);
+ if (cmp != null && cmp.size() > 0) {
+ pw.print(prefix); pw.println(" enabledComponents:");
+ for (String s : cmp) {
+ pw.print(prefix); pw.print(" "); pw.println(s);
+ }
}
}
}
}
- void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState, boolean checkin) {
+ void dumpPackagesLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
+ DumpState dumpState, boolean checkin) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final Date date = new Date();
boolean printedSomething = false;
@@ -4120,6 +4129,10 @@ final class Settings {
&& !packageName.equals(ps.name)) {
continue;
}
+ if (permissionNames != null
+ && !ps.getPermissionsState().hasRequestedPermission(permissionNames)) {
+ continue;
+ }
if (!checkin && packageName != null) {
dumpState.setSharedUser(ps.sharedUser);
@@ -4131,11 +4144,11 @@ final class Settings {
pw.println("Packages:");
printedSomething = true;
}
- dumpPackageLPr(pw, " ", checkin ? "pkg" : null, ps, sdf, date, users);
+ dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users);
}
printedSomething = false;
- if (!checkin && mRenamedPackages.size() > 0) {
+ if (!checkin && mRenamedPackages.size() > 0 && permissionNames == null) {
for (final Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
if (packageName != null && !packageName.equals(e.getKey())
&& !packageName.equals(e.getValue())) {
@@ -4159,7 +4172,7 @@ final class Settings {
}
printedSomething = false;
- if (mDisabledSysPackages.size() > 0) {
+ if (mDisabledSysPackages.size() > 0 && permissionNames == null) {
for (final PackageSetting ps : mDisabledSysPackages.values()) {
if (packageName != null && !packageName.equals(ps.realName)
&& !packageName.equals(ps.name)) {
@@ -4171,17 +4184,22 @@ final class Settings {
pw.println("Hidden system packages:");
printedSomething = true;
}
- dumpPackageLPr(pw, " ", checkin ? "dis" : null, ps, sdf, date, users);
+ dumpPackageLPr(pw, " ", checkin ? "dis" : null, permissionNames, ps, sdf, date,
+ users);
}
}
}
- void dumpPermissionsLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
+ DumpState dumpState) {
boolean printedSomething = false;
for (BasePermission p : mPermissions.values()) {
if (packageName != null && !packageName.equals(p.sourcePackage)) {
continue;
}
+ if (permissionNames != null && !permissionNames.contains(p.name)) {
+ continue;
+ }
if (!printedSomething) {
if (dumpState.onTitlePrinted())
pw.println();
@@ -4211,13 +4229,17 @@ final class Settings {
}
}
- void dumpSharedUsersLPr(PrintWriter pw, String packageName, DumpState dumpState,
- boolean checkin) {
+ void dumpSharedUsersLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
+ DumpState dumpState, boolean checkin) {
boolean printedSomething = false;
for (SharedUserSetting su : mSharedUsers.values()) {
if (packageName != null && su != dumpState.getSharedUser()) {
continue;
}
+ if (permissionNames != null
+ && !su.getPermissionsState().hasRequestedPermission(permissionNames)) {
+ continue;
+ }
if (!checkin) {
if (!printedSomething) {
if (dumpState.onTitlePrinted())
@@ -4235,7 +4257,7 @@ final class Settings {
pw.print(prefix); pw.print("userId="); pw.println(su.userId);
PermissionsState permissionsState = su.getPermissionsState();
- dumpInstallPermissionsLPr(pw, prefix, permissionsState);
+ dumpInstallPermissionsLPr(pw, prefix, permissionNames, permissionsState);
for (int userId : UserManagerService.getInstance().getUserIds()) {
final int[] gids = permissionsState.computeGids(userId);
@@ -4244,7 +4266,7 @@ final class Settings {
if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
dumpGidsLPr(pw, prefix + " ", gids);
- dumpRuntimePermissionsLPr(pw, prefix + " ", permissions);
+ dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissions);
}
}
} else {
@@ -4289,11 +4311,15 @@ final class Settings {
}
}
- void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix,
+ void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
List<PermissionState> permissionStates) {
if (!permissionStates.isEmpty()) {
pw.print(prefix); pw.println("runtime permissions:");
for (PermissionState permissionState : permissionStates) {
+ if (permissionNames != null
+ && !permissionNames.contains(permissionState.getName())) {
+ continue;
+ }
pw.print(prefix); pw.print(" "); pw.print(permissionState.getName());
pw.print(", granted="); pw.print(permissionState.isGranted());
pw.print(", flags=0x"); pw.println(Integer.toHexString(
@@ -4302,12 +4328,16 @@ final class Settings {
}
}
- void dumpInstallPermissionsLPr(PrintWriter pw, String prefix,
+ void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
PermissionsState permissionsState) {
List<PermissionState> permissionStates = permissionsState.getInstallPermissionStates();
if (!permissionStates.isEmpty()) {
pw.print(prefix); pw.println("install permissions:");
for (PermissionState permissionState : permissionStates) {
+ if (permissionNames != null
+ && !permissionNames.contains(permissionState.getName())) {
+ continue;
+ }
pw.print(prefix); pw.print(" "); pw.print(permissionState.getName());
pw.print(", granted="); pw.print(permissionState.isGranted());
pw.print(", flags=0x"); pw.println(Integer.toHexString(