Merge "Implement dual-permission model for storage."

This commit is contained in:
Jeff Sharkey
2019-03-20 23:49:08 +00:00
committed by Android (Google) Code Review
9 changed files with 271 additions and 20 deletions

View File

@@ -339,6 +339,7 @@ package android.app {
field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
field public static final String OPSTR_GPS = "android:gps";
field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
@@ -1649,6 +1650,7 @@ package android.content.pm {
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
@@ -1719,7 +1721,7 @@ package android.content.pm {
method public void onPermissionsChanged(int);
}
@IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
@IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
}
public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {

View File

@@ -172,6 +172,7 @@ package android.app {
field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
field public static final String OPSTR_GPS = "android:gps";
field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
@@ -659,6 +660,7 @@ package android.content.pm {
method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80

View File

@@ -48,7 +48,6 @@ import android.util.LongSparseLongArray;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Immutable;
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsCallback;
@@ -1098,6 +1097,8 @@ public class AppOpsManager {
/** @hide Write media of image type. */
public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images";
/** @hide Has a legacy (non-isolated) view of storage. */
@TestApi
@SystemApi
public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
/** @hide Interact with accessibility. */
@SystemApi

View File

@@ -3064,6 +3064,15 @@ public abstract class PackageManager {
@SystemApi
public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 1 << 9;
/**
* Permission flag: The permission should not be shown in the UI.
*
* @hide
*/
@SystemApi
@TestApi
public static final int FLAG_PERMISSION_HIDDEN = 1 << 10;
/**
* Mask for all permission flags present in Android P
*
@@ -3082,7 +3091,7 @@ public abstract class PackageManager {
*
* @hide
*/
public static final int MASK_PERMISSION_FLAGS_ALL = 0x3FF;
public static final int MASK_PERMISSION_FLAGS_ALL = 0x7FF;
/**
* Injected activity in app that forwards user to setting activity of that app.
@@ -3793,6 +3802,7 @@ public abstract class PackageManager {
FLAG_PERMISSION_GRANTED_BY_DEFAULT,
FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED,
FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED,
FLAG_PERMISSION_HIDDEN,
/*
FLAG_PERMISSION_REVOKE_WHEN_REQUESED
*/
@@ -6586,6 +6596,7 @@ public abstract class PackageManager {
case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED";
case FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED: return "USER_SENSITIVE_WHEN_GRANTED";
case FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED: return "USER_SENSITIVE_WHEN_DENIED";
case FLAG_PERMISSION_HIDDEN: return "HIDDEN";
default: return Integer.toString(flag);
}
}

View File

@@ -819,8 +819,7 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_sdcardRead"
android:description="@string/permdesc_sdcardRead"
android:protectionLevel="dangerous"
android:permissionFlags="removed" />
android:protectionLevel="dangerous" />
<!-- Allows an application to write to external storage.
<p class="note"><strong>Note:</strong> If <em>both</em> your <a
@@ -841,8 +840,7 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_sdcardWrite"
android:description="@string/permdesc_sdcardWrite"
android:protectionLevel="dangerous"
android:permissionFlags="removed" />
android:protectionLevel="dangerous" />
<!-- Runtime permission controlling access to the user's shared aural media
collection. -->

View File

@@ -202,17 +202,15 @@
<new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</split-permission>
<!-- Apps holding either the legacy READ or WRITE permissions will inherit
the ability to <em>read</em> new typed permissions in the Q release; they
won't gain the ability to <em>write</em> that content. -->
<!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised -->
<!-- STOPSHIP: change targetSdk to Q when SDK version finalised -->
<!-- Old apps might not understand the modern permission model, hence their view needs to be expanded -->
<split-permission name="android.permission.READ_EXTERNAL_STORAGE"
targetSdk="10000">
<new-permission name="android.permission.READ_MEDIA_AUDIO" />
<new-permission name="android.permission.READ_MEDIA_VIDEO" />
<new-permission name="android.permission.READ_MEDIA_IMAGES" />
</split-permission>
<!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised -->
<!-- STOPSHIP: change targetSdk to Q when SDK version finalised -->
<split-permission name="android.permission.WRITE_EXTERNAL_STORAGE"
targetSdk="10000">
<new-permission name="android.permission.READ_MEDIA_AUDIO" />
@@ -220,6 +218,20 @@
<new-permission name="android.permission.READ_MEDIA_IMAGES" />
</split-permission>
<!-- An app using the typed media permissions might be grandfathered and then uses the old storage model -->
<split-permission name="android.permission.READ_MEDIA_AUDIO">
<new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
<new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
</split-permission>
<split-permission name="android.permission.READ_MEDIA_VIDEO">
<new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
<new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
</split-permission>
<split-permission name="android.permission.READ_MEDIA_IMAGES">
<new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
<new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
</split-permission>
<!-- This is a list of all the libraries available for application
code to link against. -->

View File

@@ -21,6 +21,9 @@ import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -74,6 +77,7 @@ import android.content.res.ObbInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
@@ -301,6 +305,19 @@ class StorageManagerService extends IStorageManager.Stub
private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
private static final String[] LEGACY_STORAGE_PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private static final String[] ALL_STORAGE_PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_MEDIA_AUDIO,
Manifest.permission.READ_MEDIA_VIDEO,
Manifest.permission.READ_MEDIA_IMAGES
};
private final AtomicFile mSettingsFile;
/**
@@ -1693,23 +1710,27 @@ class StorageManagerService extends IStorageManager.Stub
* If we're enabling isolated storage, we need to remember which existing
* apps have already been using shared storage, and grant them legacy access
* to keep them running smoothly.
*
* @see com.android.server.pm.permission.PermissionManagerService
* #applyLegacyStoragePermissionModel
*/
private void applyLegacyStorage() {
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
for (int userId : um.getUserIds()) {
final UserHandle user = UserHandle.of(userId);
final PackageManager pm;
try {
pm = mContext.createPackageContextAsUser(mContext.getPackageName(),
0, UserHandle.of(userId)).getPackageManager();
pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
user).getPackageManager();
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(new String[] {
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
}, MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(
LEGACY_STORAGE_PERMISSIONS,
MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
| GET_PERMISSIONS);
for (PackageInfo pkg : pkgs) {
final int uid = pkg.applicationInfo.uid;
final String packageName = pkg.applicationInfo.packageName;
@@ -1722,8 +1743,28 @@ class StorageManagerService extends IStorageManager.Stub
Log.d(TAG, "Found " + uid + " " + packageName
+ " with granted storage access, last accessed " + lastAccess);
if (lastAccess > 0) {
appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE,
uid, packageName, AppOpsManager.MODE_ALLOWED);
appOps.setUidMode(AppOpsManager.OP_LEGACY_STORAGE, uid,
AppOpsManager.MODE_ALLOWED);
// Grandfather pre-Q app by granting all permissions and fixing them. The user
// needs to uninstall the app to revoke the permissions.
// TODO: Deal with shard Uids
if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
for (String perm : ALL_STORAGE_PERMISSIONS) {
if (ArrayUtils.contains(pkg.requestedPermissions, perm)) {
pm.grantRuntimePermission(packageName, perm, user);
int flags = FLAG_PERMISSION_SYSTEM_FIXED;
if (!ArrayUtils.contains(LEGACY_STORAGE_PERMISSIONS, perm)) {
flags |= FLAG_PERMISSION_HIDDEN;
}
pm.updatePermissionFlags(perm, packageName,
FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_HIDDEN,
flags, user);
}
}
}
}
}
}

View File

@@ -17,14 +17,20 @@
package com.android.server.pm.permission;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_MEDIA_AUDIO;
import static android.Manifest.permission.READ_MEDIA_IMAGES;
import static android.Manifest.permission.READ_MEDIA_VIDEO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.permissionToOp;
import static android.app.AppOpsManager.permissionToOpCode;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
@@ -1149,6 +1155,8 @@ public class PermissionManagerService {
updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
permissionsState, pkg, updatedUserIds);
updatedUserIds = applyLegacyStoragePermissionModel(origPermissions, permissionsState,
pkg, updatedUserIds);
setAppOpsLocked(permissionsState, pkg);
}
@@ -1467,6 +1475,179 @@ public class PermissionManagerService {
return updatedUserIds;
}
/**
* Pre-Q apps use READ/WRITE_EXTERNAL_STORAGE, post-Q apps use READ_MEDIA_AUDIO/VIDEO/IMAGES.
*
* <p>There is the special case of the grandfathered post-Q app that has all legacy and modern
* permissions system-fixed granted. The only way to remove these permissions is to uninstall
* the app.
*
* @param origPs The permission state of the package before the update
* @param ps The permissions state of the package
* @param pkg The package
* @param updatedUserIds The userIds we have already been updated before
*
* @return The userIds that have been updated
*
* @see com.android.server.StorageManagerService#applyLegacyStorage()
*/
private @NonNull int[] applyLegacyStoragePermissionModel(@NonNull PermissionsState origPs,
@NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
@NonNull int[] updatedUserIds) {
AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class);
int[] users = UserManagerService.getInstance().getUserIds();
boolean isQApp = pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
boolean isPreMApp = pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M;
int appId = getAppId(pkg.applicationInfo.uid);
int numRequestedPerms = pkg.requestedPermissions.size();
for (int i = 0; i < numRequestedPerms; i++) {
String perm = pkg.requestedPermissions.get(i);
boolean isLegacyStoragePermission = false;
boolean isModernStoragePermission = false;
switch (perm) {
case READ_EXTERNAL_STORAGE:
case WRITE_EXTERNAL_STORAGE:
isLegacyStoragePermission = true;
break;
case READ_MEDIA_AUDIO:
case READ_MEDIA_VIDEO:
case READ_MEDIA_IMAGES:
isModernStoragePermission = true;
break;
default:
// 'perm' is not a storage permission, skip it
continue;
}
BasePermission bp = mSettings.getPermissionLocked(perm);
for (int userId : users) {
boolean useLegacyStoragePermissionModel;
if (isQApp) {
useLegacyStoragePermissionModel = appOpsManager.checkOperationUnchecked(
OP_LEGACY_STORAGE, getUid(userId, appId), pkg.packageName)
== MODE_ALLOWED;
} else {
useLegacyStoragePermissionModel = true;
}
int origCombinedLegacyFlags =
origPs.getPermissionFlags(READ_EXTERNAL_STORAGE, userId)
| origPs.getPermissionFlags(WRITE_EXTERNAL_STORAGE, userId);
int origCombinedModernFlags = origPs.getPermissionFlags(READ_MEDIA_AUDIO, userId)
| origPs.getPermissionFlags(READ_MEDIA_VIDEO, userId)
| origPs.getPermissionFlags(READ_MEDIA_IMAGES, userId);
boolean oldPermAreLegacyStorageModel =
(origCombinedLegacyFlags & FLAG_PERMISSION_HIDDEN) == 0;
boolean oldPermAreModernStorageModel =
(origCombinedModernFlags & FLAG_PERMISSION_HIDDEN) == 0;
if (oldPermAreLegacyStorageModel && oldPermAreModernStorageModel) {
// This only happens after an platform upgrade from before Q
oldPermAreModernStorageModel = false;
}
boolean shouldBeRestricted;
boolean shouldBeFixed;
boolean shouldBeGranted = false;
boolean shouldBeRevoked = false;
int userFlags = -1;
if (useLegacyStoragePermissionModel) {
shouldBeRestricted = isModernStoragePermission;
shouldBeFixed = isQApp || isModernStoragePermission;
if (shouldBeFixed) {
userFlags = 0;
shouldBeGranted = true;
shouldBeRevoked = false;
} else if (oldPermAreModernStorageModel) {
// Inherit grant state on permission model change
userFlags = origCombinedModernFlags;
shouldBeGranted = origPs.hasRuntimePermission(READ_MEDIA_AUDIO, userId)
|| origPs.hasRuntimePermission(READ_MEDIA_VIDEO, userId)
|| origPs.hasRuntimePermission(READ_MEDIA_IMAGES, userId);
shouldBeRevoked = !shouldBeGranted;
}
} else {
shouldBeRestricted = isLegacyStoragePermission;
shouldBeFixed = isLegacyStoragePermission;
if (shouldBeFixed) {
userFlags = 0;
shouldBeGranted = true;
shouldBeRevoked = false;
} else if (oldPermAreLegacyStorageModel) {
// Inherit grant state on permission model change
userFlags = origCombinedLegacyFlags;
shouldBeGranted = origPs.hasRuntimePermission(READ_EXTERNAL_STORAGE, userId)
|| origPs.hasRuntimePermission(WRITE_EXTERNAL_STORAGE, userId);
if ((origCombinedLegacyFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0
&& !isPreMApp) {
shouldBeGranted = false;
}
shouldBeRevoked = !shouldBeGranted;
}
}
// Granted permissions can never be user fixed
if (shouldBeGranted & userFlags != -1) {
userFlags &= ~FLAG_PERMISSION_USER_FIXED;
}
boolean changed = false;
synchronized (mLock) {
if (shouldBeGranted) {
if (isPreMApp) {
setAppOpMode(perm, pkg, userId, MODE_ALLOWED);
} else if (!ps.hasRuntimePermission(perm, userId)) {
ps.grantRuntimePermission(bp, userId);
changed = true;
}
}
if (shouldBeRevoked) {
if (isPreMApp) {
setAppOpMode(perm, pkg, userId, MODE_IGNORED);
} else if (ps.hasRuntimePermission(perm, userId)) {
ps.revokeRuntimePermission(bp, userId);
changed = true;
}
}
if (shouldBeFixed) {
changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm),
userId, FLAG_PERMISSION_SYSTEM_FIXED, FLAG_PERMISSION_SYSTEM_FIXED);
}
if (userFlags != -1) {
changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm),
userId, USER_PERMISSION_FLAGS, userFlags);
}
changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm), userId,
FLAG_PERMISSION_HIDDEN,
shouldBeRestricted ? FLAG_PERMISSION_HIDDEN : 0);
}
if (changed) {
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
}
}
}
return updatedUserIds;
}
/**
* Fix app-op modes for runtime permissions.
*

View File

@@ -19,6 +19,9 @@
},
{
"include-filter": "android.permission.cts.PermissionFlagsTest"
},
{
"include-filter": "android.permission.cts.DualStoragePermissionModelTest"
}
]
},