diff options
author | Philip P. Moltmann <moltmann@google.com> | 2019-07-17 08:32:29 -0700 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-07-18 04:09:48 +0000 |
commit | 94c25a7d11b75ad69df7e1ed0bc58750ee3d7c8a (patch) | |
tree | 22de82c8c19472a7743ea6047366eb5e8883300f | |
parent | 650c60b18dba4f98ef3f5916479611a54b2571aa (diff) | |
download | platform_cts-94c25a7d11b75ad69df7e1ed0bc58750ee3d7c8a.tar.gz platform_cts-94c25a7d11b75ad69df7e1ed0bc58750ee3d7c8a.tar.bz2 platform_cts-94c25a7d11b75ad69df7e1ed0bc58750ee3d7c8a.zip |
Test restricted permission vs shared uid
- esp. read-external-storage perm
- the rest behaves the same
Bug: 136129296
Test: atest RestrictedStoragePermissionSharedUidTest RestrictedPermissionsTest
Change-Id: I178d8ab6b09a518f8f9149fbe66b54fe0324a0dd
(cherry picked from commit 5bcbdeb1739b6f4cad7e9e303c04dafaa1fa09a3)
15 files changed, 632 insertions, 0 deletions
diff --git a/tests/tests/permission2/AndroidTest.xml b/tests/tests/permission2/AndroidTest.xml index 9e78d64d10a..bcab1535a0c 100644 --- a/tests/tests/permission2/AndroidTest.xml +++ b/tests/tests/permission2/AndroidTest.xml @@ -39,6 +39,12 @@ <option name="push" value="CtsStoragePermissionsUserOptInSdk22.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk22.apk" /> <option name="push" value="CtsStoragePermissionsUserOptInSdk28.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk28.apk" /> <option name="push" value="CtsStoragePermissionsUserOptOutSdk29.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk29.apk" /> + <option name="push" value="CtsLegacyStorageNotIsolatedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageNotIsolatedWithSharedUid.apk" /> + <option name="push" value="CtsLegacyStorageIsolatedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageIsolatedWithSharedUid.apk" /> + <option name="push" value="CtsLegacyStorageRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageRestrictedWithSharedUid.apk" /> + <option name="push" value="CtsLegacyStorageRestrictedSdk28WithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageRestrictedSdk28WithSharedUid.apk" /> + <option name="push" value="CtsSMSRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsSMSRestrictedWithSharedUid.apk" /> + <option name="push" value="CtsSMSNotRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsSMSNotRestrictedWithSharedUid.apk" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp new file mode 100644 index 00000000000..6ee6120595e --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test_helper_app { + name: "CtsLegacyStorageIsolatedWithSharedUid", + defaults: ["cts_defaults"], + + sdk_version: "current", + + test_suites: [ + "cts", + "vts", + "general-tests", + "cts_instant", + ] +}
\ No newline at end of file diff --git a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml new file mode 100644 index 00000000000..9054889ede4 --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.permission2.cts.legacystoragewithshareduid.isolated" + android:versionCode="1" + android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid"> + + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + + <application android:label="CtsLegacyStorageIsolatedWithSharedUid" /> +</manifest> diff --git a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp new file mode 100644 index 00000000000..63c2a1470ad --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test_helper_app { + name: "CtsLegacyStorageNotIsolatedWithSharedUid", + defaults: ["cts_defaults"], + + sdk_version: "current", + + test_suites: [ + "cts", + "vts", + "general-tests", + "cts_instant", + ] +}
\ No newline at end of file diff --git a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml new file mode 100644 index 00000000000..179f19a4507 --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.permission2.cts.legacystoragewithshareduid.notisolated" + android:versionCode="1" + android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid"> + + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + + <application android:label="CtsLegacyStorageNotIsolatedWithSharedUid" + android:requestLegacyExternalStorage="true" /> +</manifest> diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp new file mode 100644 index 00000000000..50ac715f38e --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test_helper_app { + name: "CtsLegacyStorageRestrictedSdk28WithSharedUid", + defaults: ["cts_defaults"], + + sdk_version: "current", + + test_suites: [ + "cts", + "vts", + "general-tests", + "cts_instant", + ] +}
\ No newline at end of file diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml new file mode 100644 index 00000000000..89cadcdbefa --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.permission2.cts.legacystoragewithshareduid.restrictedsdk28" + android:versionCode="1" + android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid"> + + <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" /> + + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + + <application android:label="CtsLegacyStorageRestrictedSdk28WithSharedUid" /> +</manifest> diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp new file mode 100644 index 00000000000..78068f95d38 --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test_helper_app { + name: "CtsLegacyStorageRestrictedWithSharedUid", + defaults: ["cts_defaults"], + + sdk_version: "current", + + test_suites: [ + "cts", + "vts", + "general-tests", + "cts_instant", + ] +}
\ No newline at end of file diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml new file mode 100644 index 00000000000..5791147151a --- /dev/null +++ b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.permission2.cts.legacystoragewithshareduid.restricted" + android:versionCode="1" + android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid"> + + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + + <application android:label="CtsLegacyStorageRestrictedWithSharedUid" /> +</manifest> diff --git a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp new file mode 100644 index 00000000000..9806571b2c7 --- /dev/null +++ b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test_helper_app { + name: "CtsSMSNotRestrictedWithSharedUid", + defaults: ["cts_defaults"], + + sdk_version: "current", + + test_suites: [ + "cts", + "vts", + "general-tests", + "cts_instant", + ] +}
\ No newline at end of file diff --git a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml new file mode 100644 index 00000000000..83c43a2a403 --- /dev/null +++ b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.permission2.cts.smswithshareduid.notrestricted" + android:versionCode="1" + android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid"> + + <uses-permission android:name="android.permission.READ_SMS" /> + + <application android:label="CtsSMSNotRestrictedWithSharedUid" /> +</manifest> diff --git a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp new file mode 100644 index 00000000000..ec6d1285b97 --- /dev/null +++ b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test_helper_app { + name: "CtsSMSRestrictedWithSharedUid", + defaults: ["cts_defaults"], + + sdk_version: "current", + + test_suites: [ + "cts", + "vts", + "general-tests", + "cts_instant", + ] +}
\ No newline at end of file diff --git a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml new file mode 100644 index 00000000000..a497392e2f1 --- /dev/null +++ b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.permission2.cts.smswithshareduid.restricted" + android:versionCode="1" + android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid"> + + <uses-permission android:name="android.permission.READ_SMS" /> + + <application android:label="CtsSMSRestrictedWithSharedUid" /> +</manifest> diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java index 996630ac12f..7dca607ed4a 100644 --- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java +++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java @@ -16,6 +16,7 @@ package android.permission2.cts; +import static android.Manifest.permission.READ_SMS; import static android.permission.cts.PermissionUtils.eventually; import static android.permission.cts.PermissionUtils.isGranted; import static android.permission.cts.PermissionUtils.isPermissionGranted; @@ -104,6 +105,18 @@ public class RestrictedPermissionsTest { private static final String PKG = "android.permission2.cts.restrictedpermissionuser"; + private static final String APK_USES_SMS_RESTRICTED_SHARED_UID = + "/data/local/tmp/cts/permissions2/CtsSMSRestrictedWithSharedUid.apk"; + + private static final String PKG_USES_SMS_RESTRICTED_SHARED_UID = + "android.permission2.cts.smswithshareduid.restricted"; + + private static final String APK_USES_SMS_NOT_RESTRICTED_SHARED_UID = + "/data/local/tmp/cts/permissions2/CtsSMSNotRestrictedWithSharedUid.apk"; + + private static final String PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID = + "android.permission2.cts.smswithshareduid.notrestricted"; + private static final long UI_TIMEOUT = 5000L; private static @NonNull BroadcastReceiver sCommandReceiver; @@ -681,6 +694,19 @@ public class RestrictedPermissionsTest { assertNoRestrictedPermissionWhitelisted(); } + @Test + @AppModeFull + public void shareUidBetweenRestrictedAndNotRestrictedApp() throws Exception { + runShellCommand( + "pm install -g --restrict-permissions " + APK_USES_SMS_RESTRICTED_SHARED_UID); + runShellCommand("pm install -g " + APK_USES_SMS_NOT_RESTRICTED_SHARED_UID); + + eventually( + () -> assertThat(isGranted(PKG_USES_SMS_RESTRICTED_SHARED_UID, READ_SMS)).isTrue()); + // The apps share a UID, hence the whitelisting is shared too + assertThat(isGranted(PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID, READ_SMS)).isTrue(); + } + private static void installRestrictedPermissionUserApp(@NonNull SessionParams params) throws Exception { final CountDownLatch installLatch = new CountDownLatch(1); @@ -1113,6 +1139,8 @@ public class RestrictedPermissionsTest { @After public void uninstallApp() { runShellCommand("pm uninstall " + PKG); + runShellCommand("pm uninstall " + PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID); + runShellCommand("pm uninstall " + PKG_USES_SMS_RESTRICTED_SHARED_UID); } private static @NonNull Context getContext() { diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java new file mode 100644 index 00000000000..1d0ded2ccd3 --- /dev/null +++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.permission2.cts; + +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE; +import static android.permission.cts.PermissionUtils.eventually; +import static android.permission.cts.PermissionUtils.isGranted; +import static android.permission2.cts.RestrictedStoragePermissionSharedUidTest.StorageState.DENIED; +import static android.permission2.cts.RestrictedStoragePermissionSharedUidTest.StorageState.ISOLATED; +import static android.permission2.cts.RestrictedStoragePermissionSharedUidTest.StorageState.NON_ISOLATED; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static com.google.common.truth.Truth.assertThat; + +import static java.lang.Integer.min; + +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Build; +import android.platform.test.annotations.AppModeFull; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import java.util.ArrayList; + +@AppModeFull(reason = "Instant apps cannot access other app's properties") +@RunWith(Parameterized.class) +public class RestrictedStoragePermissionSharedUidTest { + private static final String LOG_TAG = + RestrictedStoragePermissionSharedUidTest.class.getSimpleName(); + + public enum StorageState { + /** The app has non-isolated storage */ + NON_ISOLATED, + + /** The app has isolated storage */ + ISOLATED, + + /** The read-external-storage permission cannot be granted */ + DENIED + } + + /** + * An app that is tested + */ + private static class TestApp { + private static @NonNull Context sContext = + InstrumentationRegistry.getInstrumentation().getContext(); + private static @NonNull AppOpsManager sAppOpsManager = + sContext.getSystemService(AppOpsManager.class); + private static @NonNull PackageManager sPackageManager = sContext.getPackageManager(); + + private final String mApk; + private final String mPkg; + + public final boolean isRestricted; + public final boolean hasRequestedLegacyExternalStorage; + + TestApp(@NonNull String apk, @NonNull String pkg, boolean isRestricted, + @NonNull boolean hasRequestedLegacyExternalStorage) { + mApk = apk; + mPkg = pkg; + + this.isRestricted = isRestricted; + this.hasRequestedLegacyExternalStorage = hasRequestedLegacyExternalStorage; + } + + /** + * Assert that the read-external-storage permission was granted or not granted. + * + * @param expectGranted {@code true} if the permission is expected to be granted + */ + void assertStoragePermGranted(boolean expectGranted) { + eventually(() -> assertThat(isGranted(mPkg, READ_EXTERNAL_STORAGE)).named( + this + " read storage granted").isEqualTo(expectGranted)); + } + + /** + * Assert that the app has non-isolated storage + * + * @param expectGranted {@code true} if the app is expected to have non-isolated storage + */ + void assertHasNotIsolatedStorage(boolean expectHasNotIsolatedStorage) { + eventually(() -> runWithShellPermissionIdentity(() -> { + int uid = sContext.getPackageManager().getPackageUid(mPkg, 0); + if (expectHasNotIsolatedStorage) { + assertThat(sAppOpsManager.unsafeCheckOpRawNoThrow(OPSTR_LEGACY_STORAGE, uid, + mPkg)).named(this + " legacy storage mode").isEqualTo(MODE_ALLOWED); + } else { + assertThat(sAppOpsManager.unsafeCheckOpRawNoThrow(OPSTR_LEGACY_STORAGE, uid, + mPkg)).named(this + " legacy storage mode").isNotEqualTo(MODE_ALLOWED); + } + })); + } + + int getTargetSDK() throws Exception { + return sPackageManager.getApplicationInfo(mPkg, 0).targetSdkVersion; + } + + void install() { + if (isRestricted) { + runShellCommand("pm install -g --restrict-permissions " + mApk); + } else { + runShellCommand("pm install -g " + mApk); + } + } + + void uninstall() { + runShellCommand("pm uninstall " + mPkg); + } + + @Override + public String toString() { + return mPkg.substring(PKG_PREFIX.length()); + } + } + + /** + * Placeholder for "no app". The properties are chosen that when combined with another app, the + * other app always decides the resulting property, + */ + private static class NoApp extends TestApp { + NoApp() { + super("", PKG_PREFIX + "(none)", true, false); + } + + void assertStoragePermGranted(boolean ignored) { + // empty + } + + void assertHasNotIsolatedStorage(boolean ignored) { + // empty + } + + @Override + int getTargetSDK() { + return 10000; + } + + @Override + public void install() { + // empty + } + + @Override + public void uninstall() { + // empty + } + } + + private static final String APK_PATH = "/data/local/tmp/cts/permissions2/"; + private static final String PKG_PREFIX = "android.permission2.cts.legacystoragewithshareduid."; + + private static final TestApp[] TEST_APPS = new TestApp[]{ + new TestApp(APK_PATH + "CtsLegacyStorageNotIsolatedWithSharedUid.apk", + PKG_PREFIX + "notisolated", false, true), + new TestApp(APK_PATH + "CtsLegacyStorageIsolatedWithSharedUid.apk", + PKG_PREFIX + "isolated", false, false), + new TestApp(APK_PATH + "CtsLegacyStorageRestrictedWithSharedUid.apk", + PKG_PREFIX + "restricted", true, false), + new TestApp(APK_PATH + "CtsLegacyStorageRestrictedSdk28WithSharedUid.apk", + PKG_PREFIX + "restrictedsdk28", true, true), + new NoApp()}; + + /** + * First app to be tested. This is the first in an entry created by {@link + * #getTestAppCombinations} + */ + @Parameter(0) + public @NonNull TestApp app1; + + /** + * Second app to be tested. This is the second in an entry created by {@link + * #getTestAppCombinations} + */ + @Parameter(1) + public @NonNull TestApp app2; + + /** + * Run this test for all combination of two tests-apps out of {@link #TEST_APPS}. This includes + * the {@link NoApp}, i.e. we also test a single test-app by itself. + * + * @return All combinations of two test-apps + */ + @Parameters(name = "{0} and {1}") + public static Iterable<Object[]> getTestAppCombinations() { + ArrayList<Object[]> parameters = new ArrayList<>(); + + for (int firstApp = 0; firstApp < TEST_APPS.length; firstApp++) { + for (int secondApp = firstApp + 1; secondApp < TEST_APPS.length; secondApp++) { + parameters.add(new Object[]{TEST_APPS[firstApp], TEST_APPS[secondApp]}); + } + } + + return parameters; + } + + @Test + public void checkExceptedStorageStateForAppsSharingUid() throws Exception { + app1.install(); + app2.install(); + + int targetSDK = min(app1.getTargetSDK(), app2.getTargetSDK()); + boolean isRestricted = app1.isRestricted && app2.isRestricted; + boolean hasRequestedLegacyExternalStorage = + app1.hasRequestedLegacyExternalStorage || app2.hasRequestedLegacyExternalStorage; + + StorageState expectedState; + if (isRestricted) { + if (targetSDK < Build.VERSION_CODES.Q) { + expectedState = DENIED; + } else { + expectedState = ISOLATED; + } + } else if (hasRequestedLegacyExternalStorage) { + expectedState = NON_ISOLATED; + } else { + expectedState = ISOLATED; + } + + Log.i(LOG_TAG, "Expected state=" + expectedState); + + app1.assertStoragePermGranted(expectedState != DENIED); + app2.assertStoragePermGranted(expectedState != DENIED); + + if (expectedState != DENIED) { + app1.assertHasNotIsolatedStorage(expectedState == NON_ISOLATED); + app2.assertHasNotIsolatedStorage(expectedState == NON_ISOLATED); + } + } + + @After + public void uninstallAllTestPackages() { + app1.uninstall(); + app2.uninstall(); + } +} |