Loading core/java/android/app/IUriGrantsManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -39,4 +39,7 @@ interface IUriGrantsManager { void clearGrantedUriPermissions(in String packageName, int userId); ParceledListSlice getUriPermissions(in String packageName, boolean incoming, boolean persistedOnly); int checkGrantUriPermission_ignoreNonSystem( int sourceUid, String targetPkg, in Uri uri, int modeFlags, int userId); } packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +35 −1 Original line number Diff line number Diff line Loading @@ -18,15 +18,18 @@ package com.android.systemui.media import android.app.Notification import android.app.PendingIntent import android.app.UriGrantsManager import android.app.smartspace.SmartspaceConfig import android.app.smartspace.SmartspaceManager import android.app.smartspace.SmartspaceSession import android.app.smartspace.SmartspaceTarget import android.content.BroadcastReceiver import android.content.ContentProvider import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.ImageDecoder Loading @@ -38,6 +41,7 @@ import android.media.session.MediaController import android.media.session.MediaSession import android.net.Uri import android.os.Parcelable import android.os.Process import android.os.UserHandle import android.provider.Settings import android.service.notification.StatusBarNotification Loading Loading @@ -497,7 +501,13 @@ class MediaDataManager( // Album art var artworkBitmap = desc.iconBitmap if (artworkBitmap == null && desc.iconUri != null) { artworkBitmap = loadBitmapFromUri(desc.iconUri!!) val appUid = try { context.packageManager.getApplicationInfo(packageName, 0)?.uid!! } catch (e: PackageManager.NameNotFoundException) { Log.w(TAG, "Could not get app UID for $packageName", e) Process.INVALID_UID } artworkBitmap = loadBitmapFromUriForUser(desc.iconUri!!, userId, appUid, packageName) } val artworkIcon = if (artworkBitmap != null) { Icon.createWithBitmap(artworkBitmap) Loading Loading @@ -674,6 +684,30 @@ class MediaDataManager( false } } /** Returns a bitmap if the user can access the given URI, else null */ private fun loadBitmapFromUriForUser( uri: Uri, userId: Int, appUid: Int, packageName: String, ): Bitmap? { try { val ugm = UriGrantsManager.getService() ugm.checkGrantUriPermission_ignoreNonSystem( appUid, packageName, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, userId) ) return loadBitmapFromUri(uri) } catch (e: SecurityException) { Log.e(TAG, "Failed to get URI permission: $e") } return null } /** * Load a bitmap from a URI * @param uri the uri to load Loading packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +122 −6 Original line number Diff line number Diff line package com.android.systemui.media import android.app.IUriGrantsManager import android.app.Notification.MediaStyle import android.app.PendingIntent import android.app.UriGrantsManager import android.app.smartspace.SmartspaceAction import android.app.smartspace.SmartspaceTarget import android.content.Intent import android.graphics.Bitmap import android.graphics.ImageDecoder import android.media.MediaDescription import android.media.MediaMetadata import android.media.session.MediaController import android.media.session.MediaSession import android.net.Uri import android.os.Bundle import android.provider.Settings import android.service.notification.StatusBarNotification import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher Loading @@ -24,6 +29,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.SbnBuilder import com.android.systemui.tuner.TunerService import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock Loading @@ -35,6 +41,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito Loading @@ -42,8 +49,10 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoSession import org.mockito.junit.MockitoJUnit import org.mockito.Mockito.`when` as whenever import org.mockito.quality.Strictness private const val KEY = "KEY" private const val KEY_2 = "KEY_2" Loading Loading @@ -95,12 +104,23 @@ class MediaDataManagerTest : SysuiTestCase() { private val clock = FakeSystemClock() @Mock private lateinit var tunerService: TunerService @Captor lateinit var tunableCaptor: ArgumentCaptor<TunerService.Tunable> @Mock private lateinit var ugm: IUriGrantsManager @Mock private lateinit var imageSource: ImageDecoder.Source private val originalSmartspaceSetting = Settings.Secure.getInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1) private lateinit var staticMockSession: MockitoSession @Before fun setup() { staticMockSession = ExtendedMockito.mockitoSession() .mockStatic<UriGrantsManager>(UriGrantsManager::class.java) .mockStatic<ImageDecoder>(ImageDecoder::class.java) .strictness(Strictness.LENIENT) .startMocking() whenever(UriGrantsManager.getService()).thenReturn(ugm) foregroundExecutor = FakeExecutor(clock) backgroundExecutor = FakeExecutor(clock) smartspaceMediaDataProvider = SmartspaceMediaDataProvider() Loading Loading @@ -166,6 +186,7 @@ class MediaDataManagerTest : SysuiTestCase() { @After fun tearDown() { staticMockSession.finishMocking() session.release() mediaDataManager.destroy() Settings.Secure.putInt(context.contentResolver, Loading @@ -174,12 +195,9 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testSetTimedOut_active_deactivatesMedia() { val data = MediaData(userId = USER_ID, initialized = true, backgroundColor = 0, app = null, appIcon = null, artist = null, song = null, artwork = null, actions = emptyList(), actionsToShowInCompact = emptyList(), packageName = "INVALID", token = null, clickIntent = null, device = null, active = true, resumeAction = null) mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = data) addNotificationAndLoad() val data = mediaDataCaptor.value assertThat(data.active).isTrue() mediaDataManager.setTimedOut(KEY, timedOut = true) assertThat(data.active).isFalse() Loading Loading @@ -626,4 +644,102 @@ class MediaDataManagerTest : SysuiTestCase() { assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo( MediaDataManager.MAX_COMPACT_ACTIONS) } @Test fun testResumeMediaLoaded_hasArtPermission_artLoaded() { // When resume media is loaded and user/app has permission to access the art URI, whenever( ugm.checkGrantUriPermission_ignoreNonSystem( anyInt(), any(), any(), anyInt(), anyInt() ) ) .thenReturn(1) val artwork = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) val uri = Uri.parse("content://example") whenever(ImageDecoder.createSource(any(), eq(uri))).thenReturn(imageSource) whenever(ImageDecoder.decodeBitmap(any(), any())).thenReturn(artwork) val desc = MediaDescription.Builder().run { setTitle(SESSION_TITLE) setIconUri(uri) build() } addResumeControlAndLoad(desc) // Then the artwork is loaded assertThat(mediaDataCaptor.value.artwork).isNotNull() } @Test fun testResumeMediaLoaded_noArtPermission_noArtLoaded() { // When resume media is loaded and user/app does not have permission to access the art URI whenever( ugm.checkGrantUriPermission_ignoreNonSystem( anyInt(), any(), any(), anyInt(), anyInt() ) ) .thenThrow(SecurityException("Test no permission")) val artwork = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) val uri = Uri.parse("content://example") whenever(ImageDecoder.createSource(any(), eq(uri))).thenReturn(imageSource) whenever(ImageDecoder.decodeBitmap(any(), any())).thenReturn(artwork) val desc = MediaDescription.Builder().run { setTitle(SESSION_TITLE) setIconUri(uri) build() } addResumeControlAndLoad(desc) // Then the artwork is not loaded assertThat(mediaDataCaptor.value.artwork).isNull() } /** * Helper function to add a media notification and capture the resulting MediaData */ private fun addNotificationAndLoad() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), eq(false)) } /** Helper function to add a resumption control and capture the resulting MediaData */ private fun addResumeControlAndLoad( desc: MediaDescription, packageName: String = PACKAGE_NAME ) { mediaDataManager.addResumptionControls( USER_ID, desc, Runnable {}, session.sessionToken, APP_NAME, pendingIntent, packageName ) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) verify(listener) .onMediaDataLoaded( eq(packageName), eq(null), capture(mediaDataCaptor), eq(true), eq(false) ) } } services/core/java/com/android/server/uri/UriGrantsManagerService.java +42 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; Loading @@ -62,6 +63,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; Loading Loading @@ -1302,6 +1304,46 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { return false; } /** * Check if the targetPkg can be granted permission to access uri by * the callingUid using the given modeFlags. See {@link #checkGrantUriPermissionUnlocked}. * * @param callingUid The uid of the grantor app that has permissions to the uri. * @param targetPkg The package name of the granted app that needs permissions to the uri. * @param uri The uri for which permissions should be granted. * @param modeFlags The modes to grant. See {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc. * @param userId The userId in which the uri is to be resolved. * @return uid of the target or -1 if permission grant not required. Returns -1 if the caller * does not hold INTERACT_ACROSS_USERS_FULL * @throws SecurityException if the grant is not allowed. */ @Override @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public int checkGrantUriPermission_ignoreNonSystem(int callingUid, String targetPkg, Uri uri, int modeFlags, int userId) { if (!isCallerIsSystemOrPrivileged()) { return Process.INVALID_UID; } final long origId = Binder.clearCallingIdentity(); try { return checkGrantUriPermissionUnlocked(callingUid, targetPkg, uri, modeFlags, userId); } finally { Binder.restoreCallingIdentity(origId); } } private boolean isCallerIsSystemOrPrivileged() { final int uid = Binder.getCallingUid(); if (uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) { return true; } return ActivityManager.checkComponentPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid, /* owningUid = */-1, /* exported = */ true) == PackageManager.PERMISSION_GRANTED; } @GuardedBy("mLock") private void writeGrantedUriPermissionsLocked() { if (DEBUG) Slog.v(TAG, "writeGrantedUriPermissions()"); Loading Loading
core/java/android/app/IUriGrantsManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -39,4 +39,7 @@ interface IUriGrantsManager { void clearGrantedUriPermissions(in String packageName, int userId); ParceledListSlice getUriPermissions(in String packageName, boolean incoming, boolean persistedOnly); int checkGrantUriPermission_ignoreNonSystem( int sourceUid, String targetPkg, in Uri uri, int modeFlags, int userId); }
packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +35 −1 Original line number Diff line number Diff line Loading @@ -18,15 +18,18 @@ package com.android.systemui.media import android.app.Notification import android.app.PendingIntent import android.app.UriGrantsManager import android.app.smartspace.SmartspaceConfig import android.app.smartspace.SmartspaceManager import android.app.smartspace.SmartspaceSession import android.app.smartspace.SmartspaceTarget import android.content.BroadcastReceiver import android.content.ContentProvider import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.ImageDecoder Loading @@ -38,6 +41,7 @@ import android.media.session.MediaController import android.media.session.MediaSession import android.net.Uri import android.os.Parcelable import android.os.Process import android.os.UserHandle import android.provider.Settings import android.service.notification.StatusBarNotification Loading Loading @@ -497,7 +501,13 @@ class MediaDataManager( // Album art var artworkBitmap = desc.iconBitmap if (artworkBitmap == null && desc.iconUri != null) { artworkBitmap = loadBitmapFromUri(desc.iconUri!!) val appUid = try { context.packageManager.getApplicationInfo(packageName, 0)?.uid!! } catch (e: PackageManager.NameNotFoundException) { Log.w(TAG, "Could not get app UID for $packageName", e) Process.INVALID_UID } artworkBitmap = loadBitmapFromUriForUser(desc.iconUri!!, userId, appUid, packageName) } val artworkIcon = if (artworkBitmap != null) { Icon.createWithBitmap(artworkBitmap) Loading Loading @@ -674,6 +684,30 @@ class MediaDataManager( false } } /** Returns a bitmap if the user can access the given URI, else null */ private fun loadBitmapFromUriForUser( uri: Uri, userId: Int, appUid: Int, packageName: String, ): Bitmap? { try { val ugm = UriGrantsManager.getService() ugm.checkGrantUriPermission_ignoreNonSystem( appUid, packageName, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, userId) ) return loadBitmapFromUri(uri) } catch (e: SecurityException) { Log.e(TAG, "Failed to get URI permission: $e") } return null } /** * Load a bitmap from a URI * @param uri the uri to load Loading
packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +122 −6 Original line number Diff line number Diff line package com.android.systemui.media import android.app.IUriGrantsManager import android.app.Notification.MediaStyle import android.app.PendingIntent import android.app.UriGrantsManager import android.app.smartspace.SmartspaceAction import android.app.smartspace.SmartspaceTarget import android.content.Intent import android.graphics.Bitmap import android.graphics.ImageDecoder import android.media.MediaDescription import android.media.MediaMetadata import android.media.session.MediaController import android.media.session.MediaSession import android.net.Uri import android.os.Bundle import android.provider.Settings import android.service.notification.StatusBarNotification import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher Loading @@ -24,6 +29,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.SbnBuilder import com.android.systemui.tuner.TunerService import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock Loading @@ -35,6 +41,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito Loading @@ -42,8 +49,10 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoSession import org.mockito.junit.MockitoJUnit import org.mockito.Mockito.`when` as whenever import org.mockito.quality.Strictness private const val KEY = "KEY" private const val KEY_2 = "KEY_2" Loading Loading @@ -95,12 +104,23 @@ class MediaDataManagerTest : SysuiTestCase() { private val clock = FakeSystemClock() @Mock private lateinit var tunerService: TunerService @Captor lateinit var tunableCaptor: ArgumentCaptor<TunerService.Tunable> @Mock private lateinit var ugm: IUriGrantsManager @Mock private lateinit var imageSource: ImageDecoder.Source private val originalSmartspaceSetting = Settings.Secure.getInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1) private lateinit var staticMockSession: MockitoSession @Before fun setup() { staticMockSession = ExtendedMockito.mockitoSession() .mockStatic<UriGrantsManager>(UriGrantsManager::class.java) .mockStatic<ImageDecoder>(ImageDecoder::class.java) .strictness(Strictness.LENIENT) .startMocking() whenever(UriGrantsManager.getService()).thenReturn(ugm) foregroundExecutor = FakeExecutor(clock) backgroundExecutor = FakeExecutor(clock) smartspaceMediaDataProvider = SmartspaceMediaDataProvider() Loading Loading @@ -166,6 +186,7 @@ class MediaDataManagerTest : SysuiTestCase() { @After fun tearDown() { staticMockSession.finishMocking() session.release() mediaDataManager.destroy() Settings.Secure.putInt(context.contentResolver, Loading @@ -174,12 +195,9 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testSetTimedOut_active_deactivatesMedia() { val data = MediaData(userId = USER_ID, initialized = true, backgroundColor = 0, app = null, appIcon = null, artist = null, song = null, artwork = null, actions = emptyList(), actionsToShowInCompact = emptyList(), packageName = "INVALID", token = null, clickIntent = null, device = null, active = true, resumeAction = null) mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = data) addNotificationAndLoad() val data = mediaDataCaptor.value assertThat(data.active).isTrue() mediaDataManager.setTimedOut(KEY, timedOut = true) assertThat(data.active).isFalse() Loading Loading @@ -626,4 +644,102 @@ class MediaDataManagerTest : SysuiTestCase() { assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo( MediaDataManager.MAX_COMPACT_ACTIONS) } @Test fun testResumeMediaLoaded_hasArtPermission_artLoaded() { // When resume media is loaded and user/app has permission to access the art URI, whenever( ugm.checkGrantUriPermission_ignoreNonSystem( anyInt(), any(), any(), anyInt(), anyInt() ) ) .thenReturn(1) val artwork = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) val uri = Uri.parse("content://example") whenever(ImageDecoder.createSource(any(), eq(uri))).thenReturn(imageSource) whenever(ImageDecoder.decodeBitmap(any(), any())).thenReturn(artwork) val desc = MediaDescription.Builder().run { setTitle(SESSION_TITLE) setIconUri(uri) build() } addResumeControlAndLoad(desc) // Then the artwork is loaded assertThat(mediaDataCaptor.value.artwork).isNotNull() } @Test fun testResumeMediaLoaded_noArtPermission_noArtLoaded() { // When resume media is loaded and user/app does not have permission to access the art URI whenever( ugm.checkGrantUriPermission_ignoreNonSystem( anyInt(), any(), any(), anyInt(), anyInt() ) ) .thenThrow(SecurityException("Test no permission")) val artwork = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) val uri = Uri.parse("content://example") whenever(ImageDecoder.createSource(any(), eq(uri))).thenReturn(imageSource) whenever(ImageDecoder.decodeBitmap(any(), any())).thenReturn(artwork) val desc = MediaDescription.Builder().run { setTitle(SESSION_TITLE) setIconUri(uri) build() } addResumeControlAndLoad(desc) // Then the artwork is not loaded assertThat(mediaDataCaptor.value.artwork).isNull() } /** * Helper function to add a media notification and capture the resulting MediaData */ private fun addNotificationAndLoad() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), eq(false)) } /** Helper function to add a resumption control and capture the resulting MediaData */ private fun addResumeControlAndLoad( desc: MediaDescription, packageName: String = PACKAGE_NAME ) { mediaDataManager.addResumptionControls( USER_ID, desc, Runnable {}, session.sessionToken, APP_NAME, pendingIntent, packageName ) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) verify(listener) .onMediaDataLoaded( eq(packageName), eq(null), capture(mediaDataCaptor), eq(true), eq(false) ) } }
services/core/java/com/android/server/uri/UriGrantsManagerService.java +42 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; Loading @@ -62,6 +63,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; Loading Loading @@ -1302,6 +1304,46 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { return false; } /** * Check if the targetPkg can be granted permission to access uri by * the callingUid using the given modeFlags. See {@link #checkGrantUriPermissionUnlocked}. * * @param callingUid The uid of the grantor app that has permissions to the uri. * @param targetPkg The package name of the granted app that needs permissions to the uri. * @param uri The uri for which permissions should be granted. * @param modeFlags The modes to grant. See {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc. * @param userId The userId in which the uri is to be resolved. * @return uid of the target or -1 if permission grant not required. Returns -1 if the caller * does not hold INTERACT_ACROSS_USERS_FULL * @throws SecurityException if the grant is not allowed. */ @Override @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public int checkGrantUriPermission_ignoreNonSystem(int callingUid, String targetPkg, Uri uri, int modeFlags, int userId) { if (!isCallerIsSystemOrPrivileged()) { return Process.INVALID_UID; } final long origId = Binder.clearCallingIdentity(); try { return checkGrantUriPermissionUnlocked(callingUid, targetPkg, uri, modeFlags, userId); } finally { Binder.restoreCallingIdentity(origId); } } private boolean isCallerIsSystemOrPrivileged() { final int uid = Binder.getCallingUid(); if (uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) { return true; } return ActivityManager.checkComponentPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid, /* owningUid = */-1, /* exported = */ true) == PackageManager.PERMISSION_GRANTED; } @GuardedBy("mLock") private void writeGrantedUriPermissionsLocked() { if (DEBUG) Slog.v(TAG, "writeGrantedUriPermissions()"); Loading