blob: aae4f84542f0e143fe83ad79e87d1a35e5877f30 [file] [log] [blame]
/*
* Copyright (C) 2018 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;
import static com.android.providers.media.util.FileCreationUtils.buildValidPickerUri;
import static com.android.providers.media.util.FileCreationUtils.insertFileInResolver;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import android.Manifest;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Process;
import android.os.UserHandle;
import android.provider.MediaStore;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class MediaGrantsTest {
private Context mIsolatedContext;
private Context mContext;
private ContentResolver mIsolatedResolver;
private DatabaseHelper mExternalDatabase;
private MediaGrants mGrants;
private static final String TEST_OWNER_PACKAGE_NAME = "com.android.test.package";
private static final int TEST_USER_ID = UserHandle.myUserId();
@BeforeClass
public static void setUpClass() {
androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
.getUiAutomation()
.adoptShellPermissionIdentity(
Manifest.permission.LOG_COMPAT_CHANGE,
Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.INTERACT_ACROSS_USERS,
Manifest.permission.WRITE_MEDIA_STORAGE,
Manifest.permission.MANAGE_EXTERNAL_STORAGE);
}
@Before
/** Clean up and old files / force a clean slate before each test case. */
public void setUp() {
if (mIsolatedResolver != null) {
// This is necessary, we wait for all unfinished tasks to finish before we create a
// new IsolatedContext.
MediaStore.waitForIdle(mIsolatedResolver);
}
mContext = InstrumentationRegistry.getTargetContext();
mIsolatedContext = new IsolatedContext(mContext, "modern", /*asFuseThread*/ false);
mIsolatedResolver = mIsolatedContext.getContentResolver();
mExternalDatabase = ((IsolatedContext) mIsolatedContext).getExternalDatabase();
mGrants = new MediaGrants(mExternalDatabase);
}
@Test
public void testAddMediaGrants() throws Exception {
Long fileId1 = insertFileInResolver(mIsolatedResolver, "test_file1");
Long fileId2 = insertFileInResolver(mIsolatedResolver, "test_file2");
List<Uri> uris = List.of(buildValidPickerUri(fileId1), buildValidPickerUri(fileId2));
mGrants.addMediaGrantsForPackage(TEST_OWNER_PACKAGE_NAME, uris, TEST_USER_ID);
assertGrantExistsForPackage(fileId1, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
assertGrantExistsForPackage(fileId2, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
}
@Test
public void testAddDuplicateMediaGrants() throws Exception {
Long fileId1 = insertFileInResolver(mIsolatedResolver, "test_file1");
List<Uri> uris = List.of(buildValidPickerUri(fileId1));
mGrants.addMediaGrantsForPackage(TEST_OWNER_PACKAGE_NAME, uris, TEST_USER_ID);
assertGrantExistsForPackage(fileId1, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
// Add the same grant again to ensure no database insert failure.
mGrants.addMediaGrantsForPackage(TEST_OWNER_PACKAGE_NAME, uris, TEST_USER_ID);
assertGrantExistsForPackage(fileId1, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
}
@Test
public void testAddMediaGrantsRequiresPickerUri() throws Exception {
Uri invalidUri =
Uri.EMPTY
.buildUpon()
.scheme("content")
.encodedAuthority("some_authority")
.appendPath("path")
.appendPath("20180713")
.build();
assertThrows(
IllegalArgumentException.class,
() -> {
mGrants.addMediaGrantsForPackage(
TEST_OWNER_PACKAGE_NAME, List.of(invalidUri), TEST_USER_ID);
});
}
@Test
public void removeAllMediaGrantsForPackage() throws Exception {
Long fileId1 = insertFileInResolver(mIsolatedResolver, "test_file1");
Long fileId2 = insertFileInResolver(mIsolatedResolver, "test_file2");
List<Uri> uris = List.of(buildValidPickerUri(fileId1), buildValidPickerUri(fileId2));
mGrants.addMediaGrantsForPackage(TEST_OWNER_PACKAGE_NAME, uris, TEST_USER_ID);
assertGrantExistsForPackage(fileId1, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
assertGrantExistsForPackage(fileId2, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
int removed = mGrants.removeAllMediaGrantsForPackage(TEST_OWNER_PACKAGE_NAME, "test",
TEST_USER_ID);
assertEquals(2, removed);
try (Cursor c =
mExternalDatabase.runWithTransaction(
(db) ->
db.query(
MediaGrants.MEDIA_GRANTS_TABLE,
new String[] {
MediaGrants.FILE_ID_COLUMN,
MediaGrants.OWNER_PACKAGE_NAME_COLUMN
},
String.format(
"%s = '%s'",
MediaGrants.OWNER_PACKAGE_NAME_COLUMN,
TEST_OWNER_PACKAGE_NAME),
null,
null,
null,
null))) {
assertEquals(0, c.getCount());
}
}
@Test
public void removeAllMediaGrantsForPackageRequiresNonEmpty() throws Exception {
assertThrows(
IllegalArgumentException.class,
() -> {
mGrants.removeAllMediaGrantsForPackage("", "test", TEST_USER_ID);
});
}
@Test
public void removeAllMediaGrants() throws Exception {
final String secondPackageName = "com.android.test.another.package";
Long fileId1 = insertFileInResolver(mIsolatedResolver, "test_file1");
Long fileId2 = insertFileInResolver(mIsolatedResolver, "test_file2");
List<Uri> uris = List.of(buildValidPickerUri(fileId1), buildValidPickerUri(fileId2));
mGrants.addMediaGrantsForPackage(TEST_OWNER_PACKAGE_NAME, uris, TEST_USER_ID);
mGrants.addMediaGrantsForPackage(secondPackageName, uris, TEST_USER_ID);
assertGrantExistsForPackage(fileId1, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
assertGrantExistsForPackage(fileId2, TEST_OWNER_PACKAGE_NAME, TEST_USER_ID);
assertGrantExistsForPackage(fileId1, secondPackageName, TEST_USER_ID);
assertGrantExistsForPackage(fileId2, secondPackageName, TEST_USER_ID);
int removed = mGrants.removeAllMediaGrants();
assertEquals(4, removed);
try (Cursor c =
mExternalDatabase.runWithTransaction(
(db) ->
db.query(
MediaGrants.MEDIA_GRANTS_TABLE,
new String[] {
MediaGrants.FILE_ID_COLUMN,
MediaGrants.OWNER_PACKAGE_NAME_COLUMN
},
null,
null,
null,
null,
null))) {
assertEquals(0, c.getCount());
}
}
@Test
public void addMediaGrantsIsPrivileged() throws Exception {
assertThrows(
SecurityException.class,
() -> {
MediaStore.grantMediaReadForPackage(mContext, 1234, List.of());
});
}
@Test
public void mediaProviderUidCanAddMediaGrants() throws Exception {
Long fileId1 = insertFileInResolver(mIsolatedResolver, "test_file1");
Long fileId2 = insertFileInResolver(mIsolatedResolver, "test_file2");
List<Uri> uris = List.of(buildValidPickerUri(fileId1), buildValidPickerUri(fileId2));
// Use mIsolatedContext here to ensure we pass the security check.
MediaStore.grantMediaReadForPackage(mIsolatedContext, Process.myUid(), uris);
assertGrantExistsForPackage(fileId1, mContext.getPackageName(), TEST_USER_ID);
assertGrantExistsForPackage(fileId2, mContext.getPackageName(), TEST_USER_ID);
}
/**
* Assert a media grant exists in the given database.
*
* @param fileId the corresponding files._id column value.
* @param packageName i.e. com.android.test.package
* @param userId the user id of the package.
*/
private void assertGrantExistsForPackage(Long fileId, String packageName, int userId) {
try (Cursor c =
mExternalDatabase.runWithTransaction(
(db) ->
db.query(
MediaGrants.MEDIA_GRANTS_TABLE,
new String[] {
MediaGrants.FILE_ID_COLUMN,
MediaGrants.OWNER_PACKAGE_NAME_COLUMN,
MediaGrants.PACKAGE_USER_ID_COLUMN
},
String.format(
"%s = '%s' AND %s = %s AND %s = %s",
MediaGrants.OWNER_PACKAGE_NAME_COLUMN,
packageName,
MediaGrants.FILE_ID_COLUMN,
Long.toString(fileId),
MediaGrants.PACKAGE_USER_ID_COLUMN,
Integer.toString(userId)),
null,
null,
null,
null))) {
assertEquals(1, c.getCount());
Long fileIdValue;
String ownerValue;
assertTrue(c.moveToFirst());
fileIdValue = c.getLong(c.getColumnIndex(MediaGrants.FILE_ID_COLUMN));
ownerValue = c.getString(c.getColumnIndex(MediaGrants.OWNER_PACKAGE_NAME_COLUMN));
assertEquals(fileIdValue, fileId);
assertEquals(packageName, ownerValue);
}
}
}