blob: c434bd2a8f92f85442c642fa3e4e011a67c676d6 [file] [log] [blame]
/*
* Copyright (C) 2020 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 com.android.providers.media.util;
import static android.Manifest.permission.MANAGE_APP_OPS_MODES;
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.MANAGE_MEDIA;
import static android.Manifest.permission.UPDATE_APP_OPS_STATS;
import static android.app.AppOpsManager.OPSTR_NO_ISOLATED_STORAGE;
import static android.app.AppOpsManager.OPSTR_READ_MEDIA_AUDIO;
import static android.app.AppOpsManager.OPSTR_READ_MEDIA_IMAGES;
import static android.app.AppOpsManager.OPSTR_READ_MEDIA_VIDEO;
import static android.app.AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES;
import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_AUDIO;
import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES;
import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO;
import static androidx.test.InstrumentationRegistry.getContext;
import static com.android.providers.media.util.PermissionUtils.checkAppOpRequestInstallPackagesForSharedUid;
import static com.android.providers.media.util.PermissionUtils.checkIsLegacyStorageGranted;
import static com.android.providers.media.util.PermissionUtils.checkNoIsolatedStorageGranted;
import static com.android.providers.media.util.PermissionUtils.checkPermissionAccessMediaLocation;
import static com.android.providers.media.util.PermissionUtils.checkPermissionAccessMtp;
import static com.android.providers.media.util.PermissionUtils.checkPermissionDelegator;
import static com.android.providers.media.util.PermissionUtils.checkPermissionInstallPackages;
import static com.android.providers.media.util.PermissionUtils.checkPermissionManageMedia;
import static com.android.providers.media.util.PermissionUtils.checkPermissionManager;
import static com.android.providers.media.util.PermissionUtils.checkPermissionReadAudio;
import static com.android.providers.media.util.PermissionUtils.checkPermissionReadImages;
import static com.android.providers.media.util.PermissionUtils.checkPermissionReadStorage;
import static com.android.providers.media.util.PermissionUtils.checkPermissionReadVideo;
import static com.android.providers.media.util.PermissionUtils.checkPermissionSelf;
import static com.android.providers.media.util.PermissionUtils.checkPermissionShell;
import static com.android.providers.media.util.PermissionUtils.checkPermissionWriteAudio;
import static com.android.providers.media.util.PermissionUtils.checkPermissionWriteImages;
import static com.android.providers.media.util.PermissionUtils.checkPermissionWriteStorage;
import static com.android.providers.media.util.PermissionUtils.checkPermissionWriteVideo;
import static com.android.providers.media.util.PermissionUtils.checkWriteImagesOrVideoAppOps;
import static com.android.providers.media.util.TestUtils.QUERY_TYPE;
import static com.android.providers.media.util.TestUtils.RUN_INFINITE_ACTIVITY;
import static com.android.providers.media.util.TestUtils.adoptShellPermission;
import static com.android.providers.media.util.TestUtils.dropShellPermission;
import static com.android.providers.media.util.TestUtils.getPid;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import androidx.test.filters.SdkSuppress;
import androidx.test.runner.AndroidJUnit4;
import com.android.cts.install.lib.TestApp;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.Map;
@RunWith(AndroidJUnit4.class)
public class PermissionUtilsTest {
private static final TestApp TEST_APP_WITH_STORAGE_PERMS = new TestApp(
"TestAppWithStoragePerms",
"com.android.providers.media.testapp.withstorageperms", 1, false,
"MediaProviderTestAppWithStoragePerms.apk");
private static final TestApp TEST_APP_WITHOUT_PERMS = new TestApp("TestAppWithoutPerms",
"com.android.providers.media.testapp.withoutperms", 1, false,
"MediaProviderTestAppWithoutPerms.apk");
private static final TestApp LEGACY_TEST_APP = new TestApp("LegacyTestApp",
"com.android.providers.media.testapp.legacy", 1, false,
"LegacyMediaProviderTestApp.apk");
// Permission checks are based on uid, so we can pass -1 pid and avoid starting the test apps.
private static final int TEST_APP_PID = -1;
@Test
public void testConstructor() {
new PermissionUtils();
}
/**
* The best we can do here is assert that we're granted the permissions that
* we expect to be holding.
*/
@Test
public void testSelfPermissions() {
final Context context = getContext();
final int pid = android.os.Process.myPid();
final int uid = android.os.Process.myUid();
final String packageName = context.getPackageName();
assertThat(checkPermissionSelf(context, pid, uid)).isTrue();
assertThat(checkPermissionShell(context, pid, uid)).isFalse();
assertThat(checkPermissionManager(context, pid, uid, packageName, null)).isFalse();
assertThat(checkPermissionDelegator(context, pid, uid)).isFalse();
assertThat(checkPermissionManageMedia(context, pid, uid, packageName, null)).isFalse();
assertThat(checkPermissionAccessMediaLocation(context, pid, uid,
packageName, null)).isFalse();
assertThat(checkPermissionReadStorage(context, pid, uid, packageName, null)).isTrue();
assertThat(checkPermissionWriteStorage(context, pid, uid, packageName, null)).isTrue();
assertThat(checkPermissionReadAudio(context, pid, uid, packageName, null)).isTrue();
assertThat(checkPermissionWriteAudio(context, pid, uid, packageName, null)).isFalse();
assertThat(checkPermissionReadVideo(context, pid, uid, packageName, null)).isTrue();
assertThat(checkPermissionWriteVideo(context, pid, uid, packageName, null)).isFalse();
assertThat(checkPermissionReadImages(context, pid, uid, packageName, null)).isTrue();
assertThat(checkPermissionWriteImages(context, pid, uid, packageName, null)).isFalse();
assertThat(checkPermissionInstallPackages(context, pid, uid, packageName, null)).isFalse();
}
/**
* Test that {@code android:no_isolated_storage} app op is by default denied.
*/
@Test
public void testNoIsolatedStorageIsByDefaultDenied() throws Exception {
final Context context = getContext();
final int uid = android.os.Process.myUid();
final String packageName = context.getPackageName();
assertThat(checkNoIsolatedStorageGranted(context, uid, packageName, null)).isFalse();
}
@Test
public void testDefaultPermissionsOnTestAppWithStoragePerms() throws Exception {
String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS);
try {
assertThat(checkPermissionSelf(getContext(), TEST_APP_PID, testAppUid)).isFalse();
assertThat(checkPermissionShell(getContext(), TEST_APP_PID, testAppUid)).isFalse();
assertThat(
checkIsLegacyStorageGranted(getContext(), testAppUid, packageName,
null)).isFalse();
assertThat(
checkPermissionInstallPackages(getContext(), TEST_APP_PID, testAppUid,
packageName, null)).isFalse();
assertThat(
checkPermissionAccessMtp(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
assertThat(
checkPermissionWriteStorage(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
checkReadPermissions(TEST_APP_PID, testAppUid, packageName, true);
} finally {
dropShellPermission();
}
}
@Test
public void testDefaultPermissionsOnTestAppWithoutPerms() throws Exception {
String packageName = TEST_APP_WITHOUT_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS);
try {
assertThat(checkPermissionSelf(getContext(), TEST_APP_PID, testAppUid)).isFalse();
assertThat(checkPermissionShell(getContext(), TEST_APP_PID, testAppUid)).isFalse();
assertThat(
checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
assertThat(
checkPermissionManageMedia(
getContext(), TEST_APP_PID, testAppUid, packageName, null))
.isFalse();
assertThat(checkPermissionAccessMediaLocation(getContext(), TEST_APP_PID, testAppUid,
packageName, null)).isFalse();
assertThat(
checkIsLegacyStorageGranted(getContext(), testAppUid, packageName,
null)).isFalse();
assertThat(
checkPermissionInstallPackages(getContext(), TEST_APP_PID, testAppUid,
packageName,
null)).isFalse();
assertThat(
checkPermissionAccessMtp(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
assertThat(
checkPermissionWriteStorage(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
checkReadPermissions(TEST_APP_PID, testAppUid, packageName, false);
} finally {
dropShellPermission();
}
}
@Test
public void testDefaultPermissionsOnLegacyTestApp() throws Exception {
String packageName = LEGACY_TEST_APP.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS);
try {
assertThat(checkPermissionSelf(getContext(), TEST_APP_PID, testAppUid)).isFalse();
assertThat(checkPermissionShell(getContext(), TEST_APP_PID, testAppUid)).isFalse();
assertThat(
checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
assertThat(
checkPermissionManageMedia(
getContext(), TEST_APP_PID, testAppUid, packageName, null))
.isFalse();
assertThat(checkPermissionAccessMediaLocation(getContext(), TEST_APP_PID, testAppUid,
packageName, null)).isTrue();
assertThat(
checkIsLegacyStorageGranted(getContext(), testAppUid, packageName,
null)).isTrue();
assertThat(
checkPermissionInstallPackages(getContext(), TEST_APP_PID, testAppUid,
packageName, null)).isFalse();
assertThat(
checkPermissionAccessMtp(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
assertThat(
checkPermissionWriteStorage(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
checkReadPermissions(TEST_APP_PID, testAppUid, packageName, true);
} finally {
dropShellPermission();
}
}
@Test
public void testManageExternalStoragePermissionsOnTestApp() throws Exception {
final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
final int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
final String op = AppOpsManager.permissionToOp(MANAGE_EXTERNAL_STORAGE);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
modifyAppOp(testAppUid, op, AppOpsManager.MODE_ERRORED);
assertThat(checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
modifyAppOp(testAppUid, op, AppOpsManager.MODE_ALLOWED);
assertThat(checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
} finally {
dropShellPermission();
}
}
@Test
@SdkSuppress(minSdkVersion = 31, codeName = "S")
public void testManageMediaPermissionsOnTestApp() throws Exception {
final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
final int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
final String op = AppOpsManager.permissionToOp(MANAGE_MEDIA);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
modifyAppOp(testAppUid, op, AppOpsManager.MODE_ERRORED);
assertThat(
checkPermissionManageMedia(
getContext(), TEST_APP_PID, testAppUid, packageName, null))
.isFalse();
modifyAppOp(testAppUid, op, AppOpsManager.MODE_ALLOWED);
assertThat(
checkPermissionManageMedia(
getContext(), TEST_APP_PID, testAppUid, packageName, null))
.isTrue();
} finally {
dropShellPermission();
}
}
@Test
public void testSystemGalleryPermissionsOnTestApp() throws Exception {
String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
checkPermissionsForGallery(testAppUid, TEST_APP_PID, packageName, false);
final String[] SYSTEM_GALERY_APPOPS =
{OPSTR_WRITE_MEDIA_IMAGES, OPSTR_WRITE_MEDIA_VIDEO};
for (String op : SYSTEM_GALERY_APPOPS) {
modifyAppOp(testAppUid, op, AppOpsManager.MODE_ALLOWED);
}
checkPermissionsForGallery(testAppUid, TEST_APP_PID, packageName, true);
for (String op : SYSTEM_GALERY_APPOPS) {
modifyAppOp(testAppUid, op, AppOpsManager.MODE_ERRORED);
}
checkPermissionsForGallery(testAppUid, TEST_APP_PID, packageName, false);
} finally {
dropShellPermission();
}
}
@Test
public void testIsolatedStoragePermissionsOnTestApp() throws Exception {
String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
assertThat(
checkNoIsolatedStorageGranted(getContext(), testAppUid, packageName,
null)).isFalse();
modifyAppOp(testAppUid, OPSTR_NO_ISOLATED_STORAGE, AppOpsManager.MODE_ALLOWED);
assertThat(
checkNoIsolatedStorageGranted(getContext(), testAppUid, packageName,
null)).isTrue();
modifyAppOp(testAppUid, OPSTR_NO_ISOLATED_STORAGE, AppOpsManager.MODE_ERRORED);
assertThat(
checkNoIsolatedStorageGranted(getContext(), testAppUid, packageName,
null)).isFalse();
} finally {
dropShellPermission();
}
}
@Test
public void testReadVideoOnTestApp() throws Exception {
final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(
packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
assertThat(
checkPermissionReadVideo(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
modifyAppOp(testAppUid, OPSTR_READ_MEDIA_VIDEO, AppOpsManager.MODE_ERRORED);
assertThat(
checkPermissionReadVideo(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
modifyAppOp(testAppUid, OPSTR_READ_MEDIA_VIDEO, AppOpsManager.MODE_ALLOWED);
assertThat(
checkPermissionReadVideo(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
} finally {
dropShellPermission();
}
}
@Test
public void testWriteAudioOnTestApp() throws Exception {
final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(
packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
assertThat(
checkPermissionWriteAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
modifyAppOp(testAppUid, OPSTR_WRITE_MEDIA_AUDIO, AppOpsManager.MODE_ALLOWED);
assertThat(
checkPermissionWriteAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
modifyAppOp(testAppUid, OPSTR_WRITE_MEDIA_AUDIO, AppOpsManager.MODE_ERRORED);
assertThat(
checkPermissionWriteAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
} finally {
dropShellPermission();
}
}
@Test
public void testReadAudioOnTestApp() throws Exception {
final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(
packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
assertThat(
checkPermissionReadAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
modifyAppOp(testAppUid, OPSTR_READ_MEDIA_AUDIO, AppOpsManager.MODE_ERRORED);
assertThat(
checkPermissionReadAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
modifyAppOp(testAppUid, OPSTR_READ_MEDIA_AUDIO, AppOpsManager.MODE_ALLOWED);
assertThat(
checkPermissionReadAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
} finally {
dropShellPermission();
}
}
@Test
public void testReadImagesOnTestApp() throws Exception {
final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
assertThat(
checkPermissionReadImages(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
modifyAppOp(testAppUid, OPSTR_READ_MEDIA_IMAGES, AppOpsManager.MODE_ERRORED);
assertThat(
checkPermissionReadImages(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isFalse();
modifyAppOp(testAppUid, OPSTR_READ_MEDIA_IMAGES, AppOpsManager.MODE_ALLOWED);
assertThat(
checkPermissionReadImages(getContext(), TEST_APP_PID, testAppUid, packageName,
null)).isTrue();
} finally {
dropShellPermission();
}
}
@Test
public void testOpstrInstallPermissionsOnTestApp() throws Exception {
int testAppUid = getContext().getPackageManager().getPackageUid(
TEST_APP_WITH_STORAGE_PERMS.getPackageName(), 0);
String[] packageName = {TEST_APP_WITH_STORAGE_PERMS.getPackageName()};
adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
try {
assertThat(
checkAppOpRequestInstallPackagesForSharedUid(getContext(), testAppUid,
packageName, null)).isFalse();
modifyAppOp(testAppUid, OPSTR_REQUEST_INSTALL_PACKAGES, AppOpsManager.MODE_ALLOWED);
assertThat(
checkAppOpRequestInstallPackagesForSharedUid(getContext(), testAppUid,
packageName, null)).isTrue();
modifyAppOp(testAppUid, OPSTR_REQUEST_INSTALL_PACKAGES, AppOpsManager.MODE_ERRORED);
assertThat(
checkAppOpRequestInstallPackagesForSharedUid(getContext(), testAppUid,
packageName, null)).isFalse();
} finally {
dropShellPermission();
}
}
static private void modifyAppOp(int uid, String op, int mode) {
getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
}
static private void checkPermissionsForGallery(int uid, int pid, String packageName,
boolean expected) {
assertEquals(expected,
checkWriteImagesOrVideoAppOps(getContext(), uid, packageName, null));
assertEquals(expected,
checkPermissionWriteImages(getContext(), pid, uid, packageName, null));
assertEquals(expected,
checkPermissionWriteVideo(getContext(), pid, uid, packageName, null));
assertThat(
checkPermissionWriteAudio(getContext(), pid, uid, packageName, null))
.isFalse();
}
static private void checkReadPermissions(int pid, int uid, String packageName,
boolean expected) {
assertEquals(expected,
checkPermissionReadStorage(getContext(), pid, uid, packageName, null));
assertEquals(expected,
checkPermissionReadAudio(getContext(), pid, uid, packageName, null));
assertEquals(expected,
checkPermissionReadImages(getContext(), pid, uid, packageName, null));
assertEquals(expected,
checkPermissionReadVideo(getContext(), pid, uid, packageName, null));
}
}