Make storage a restricted permission - framework
This change makes storage a soft restricted permission. When the
permission is whitelisted for an app then hodlding it allows the
app to access the full SD card as on a P device. If howerver, the
permisison is not whitelisted for an app then holding it allows
accessing the visual/aural collections in media store while the
app would run in its own isolated storage sandbox.
This change also connects the opt in/out application attribute
to how external storage is mounted remocing temporary code. The
attribute was renamed to convey that opting in legacy mode is
not somethung that is desirable or would be available in the long
run.
White at this also fix the default state of app ops for restricted
permissions to avoid allowing ops for non requested restricted
permissions to every UID as component access could skip permission
checks by cannot skip app op checks.
bug:130327036
atest CtsPermission2TestCases
atest CtsPermissionTestCases
atest CtsAppOpsTestCases
atest atest CtsAppSecurityHostTestCases:android.appsecurity.cts.ExternalStorageHostTest
atest CtsAppSecurityHostTestCases:android.appsecurity.cts.PermissionsHostTest
Change-Id: Ibb23cbb6a5c66d9c3823cc13562a1b903b391ffd
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 6f92244..8eb0a03 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1752,21 +1752,21 @@
AppOpsManager.MODE_ALLOWED, // VIBRATE
AppOpsManager.MODE_ALLOWED, // READ_CONTACTS
AppOpsManager.MODE_ALLOWED, // WRITE_CONTACTS
- AppOpsManager.MODE_DEFAULT, // READ_CALL_LOG
- AppOpsManager.MODE_DEFAULT, // WRITE_CALL_LOG
+ AppOpsManager.MODE_ALLOWED, // READ_CALL_LOG
+ AppOpsManager.MODE_ALLOWED, // WRITE_CALL_LOG
AppOpsManager.MODE_ALLOWED, // READ_CALENDAR
AppOpsManager.MODE_ALLOWED, // WRITE_CALENDAR
AppOpsManager.MODE_ALLOWED, // WIFI_SCAN
AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION
AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS
AppOpsManager.MODE_ALLOWED, // CALL_PHONE
- AppOpsManager.MODE_DEFAULT, // READ_SMS
+ AppOpsManager.MODE_ALLOWED, // READ_SMS
AppOpsManager.MODE_IGNORED, // WRITE_SMS
- AppOpsManager.MODE_DEFAULT, // RECEIVE_SMS
+ AppOpsManager.MODE_ALLOWED, // RECEIVE_SMS
AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST
- AppOpsManager.MODE_DEFAULT, // RECEIVE_MMS
- AppOpsManager.MODE_DEFAULT, // RECEIVE_WAP_PUSH
- AppOpsManager.MODE_DEFAULT, // SEND_SMS
+ AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS
+ AppOpsManager.MODE_ALLOWED, // RECEIVE_WAP_PUSH
+ AppOpsManager.MODE_ALLOWED, // SEND_SMS
AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS
AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS
AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS
@@ -1800,10 +1800,10 @@
AppOpsManager.MODE_ALLOWED, // READ_PHONE_STATE
AppOpsManager.MODE_ALLOWED, // ADD_VOICEMAIL
AppOpsManager.MODE_ALLOWED, // USE_SIP
- AppOpsManager.MODE_DEFAULT, // PROCESS_OUTGOING_CALLS
+ AppOpsManager.MODE_ALLOWED, // PROCESS_OUTGOING_CALLS
AppOpsManager.MODE_ALLOWED, // USE_FINGERPRINT
AppOpsManager.MODE_ALLOWED, // BODY_SENSORS
- AppOpsManager.MODE_DEFAULT, // READ_CELL_BROADCASTS
+ AppOpsManager.MODE_ALLOWED, // READ_CELL_BROADCASTS
AppOpsManager.MODE_ERRORED, // MOCK_LOCATION
AppOpsManager.MODE_ALLOWED, // READ_EXTERNAL_STORAGE
AppOpsManager.MODE_ALLOWED, // WRITE_EXTERNAL_STORAGE
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index deb181f..9bc5f80 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -679,13 +679,13 @@
public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28;
/**
- * Value for {@link #privateFlags}: If {@code true} this app allows
- * shared/external storage media to be a sandboxed view that only contains
- * files owned by the app.
+ * Value for {@link #privateFlags}: If {@code true} this app requests
+ * full external storage access. The request may not be honored due to
+ * policy or other reasons.
*
* @hide
*/
- public static final int PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX = 1 << 29;
+ public static final int PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE = 1 << 29;
/**
* Value for {@link #privateFlags}: whether this app is pre-installed on the
@@ -723,7 +723,7 @@
PRIVATE_FLAG_HAS_FRAGILE_USER_DATA,
PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE,
PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE,
- PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX,
+ PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE,
PRIVATE_FLAG_ODM,
})
@Retention(RetentionPolicy.SOURCE)
@@ -1858,13 +1858,12 @@
}
/**
- * If {@code true} this app allows shared/external storage media to be a
- * sandboxed view that only contains files owned by the app.
+ * If {@code true} this app requested to run in the legacy storage mode.
*
* @hide
*/
- public boolean isExternalStorageSandboxAllowed() {
- return (privateFlags & PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX) != 0;
+ public boolean hasRequestedLegacyExternalStorage() {
+ return (privateFlags & PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
}
private boolean isAllowedToUseHiddenApis() {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 6ce6828..d2f0fb3 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1505,13 +1505,14 @@
* allows the app to hold that permission and whitelisting a soft restricted
* permission allows the app to hold the permission in its full, unrestricted form.
*
- * <p>The whitelisted permissions would be applied as the {@link
- * PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER installer whitelist}.
+ * <p> Permissions can also be immutably restricted which means that the whitelist
+ * state of the permission can be determined only at install time and cannot be
+ * changed on updated or at a later point via the package manager APIs.
*
- * @param permissions The restricted permissions to whitelist. Pass
- * {@link #RESTRICTED_PERMISSIONS_ALL} to whitelist all permissions and
- * <code>null</code> to clear. If you want to whitelist some permissions
- * (not all) the list must contain at least one permission.
+ * <p>The whitelisted non-immutably restricted permissions would be added to
+ * the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER installer whitelist}
+ * while the immutably restricted permissions would be added to the {@link
+ * PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM system whitelist}
*
* @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
* @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bdd80e32..0ea5200 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3700,9 +3700,9 @@
}
if (sa.getBoolean(
- R.styleable.AndroidManifestApplication_allowExternalStorageSandbox,
- owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q)) {
- ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX;
+ R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
+ owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
}
ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index f838900..14340fe 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -341,6 +341,17 @@
public static final int FLAG_SOFT_RESTRICTED = 1<<3;
/**
+ * Flag for {@link #flags}, corresponding to <code>immutablyRestricted</code>
+ * value of {@link android.R.attr#permissionFlags}.
+ *
+ * <p>This permission is restricted immutably which means that its
+ * restriction state may be specified only on the first install of
+ * the app and will stay in this initial whitelist state until
+ * the app is uninstalled.
+ */
+ public static final int FLAG_IMMUTABLY_RESTRICTED = 1<<4;
+
+ /**
* Flag for {@link #flags}, indicating that this permission has been
* installed into the system's globally defined permissions.
*/
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ed5c1b1..dde1e6a 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -1148,15 +1148,9 @@
final Context context = AppGlobals.getInitialApplication();
final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
- final boolean hasLegacy = appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
+ return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
context.getApplicationInfo().uid,
- context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
-
- // STOPSHIP: only use app-op once permission model has fully landed
- final boolean requestedLegacy = !AppGlobals.getInitialApplication().getApplicationInfo()
- .isExternalStorageSandboxAllowed();
-
- return !(hasLegacy || requestedLegacy);
+ context.getOpPackageName()) != AppOpsManager.MODE_ALLOWED;
}
static File getDirectory(String variableName, String defaultPath) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cc3b3a4..8714bf2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -828,6 +828,7 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_sdcardRead"
android:description="@string/permdesc_sdcardRead"
+ android:permissionFlags="softRestricted|immutablyRestricted"
android:protectionLevel="dangerous" />
<!-- Allows an application to write to external storage.
@@ -848,6 +849,7 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_sdcardWrite"
android:description="@string/permdesc_sdcardWrite"
+ android:permissionFlags="softRestricted|immutablyRestricted"
android:protectionLevel="dangerous" />
<!-- Allows an application to access any geographic locations persisted in the
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index bfa57e4..bbc784a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -328,6 +328,12 @@
would be granted. The weak grant depends on the permission.
-->
<flag name="softRestricted" value="0x8" />
+ <!-- This permission is restricted immutably which means that its
+ restriction state may be specified only on the first install of
+ the app and will stay in this initial whitelist state until
+ the app is uninstalled.
+ -->
+ <flag name="immutablyRestricted" value="0x10" />
</attr>
<!-- Specified the name of a group that this permission is associated
@@ -1707,17 +1713,18 @@
See {@link android.media.AudioPlaybackCaptureConfiguration} for more detail.
-->
<attr name="allowAudioPlaybackCapture" format="boolean" />
- <!-- If {@code true} this app allows shared/external storage media to be
- a sandboxed view that only contains files owned by the app.
- <p>
- Sandboxed apps can continue to discover and read media belonging to other
- apps via {@code MediaStore}.
+ <!-- If {@code true} this app would like to run under the legacy storage
+ model. Note that this may not always be respected due to policy or
+ backwards compatibility reasons.
+
+ <p>Apps not requesting legacy storage can continue to discover and
+ read media belonging to other apps via {@code MediaStore}.
<p>
The default value is:
- - {@code true} for apps with targetSdkVersion >= 29 (Q).
- - {@code false} for apps with targetSdkVersion < 29.
+ - {@code false} for apps with targetSdkVersion >= 29 (Q).
+ - {@code true} for apps with targetSdkVersion < 29.
-->
- <attr name="allowExternalStorageSandbox" format="boolean" />
+ <attr name="requestLegacyExternalStorage" format="boolean" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b7d61c8..a7af144 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2942,7 +2942,7 @@
<public name="allowClearUserDataOnFailedRestore"/>
<public name="allowAudioPlaybackCapture"/>
<public name="secureElementName" />
- <public name="allowExternalStorageSandbox"/>
+ <public name="requestLegacyExternalStorage"/>
<public name="ensuringStatusBarContrastWhenTransparent" />
<public name="ensuringNavigationBarContrastWhenTransparent" />
<public name="identifier" />