1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.permissioncontroller.tests.mocking.privacysources 18 19 import android.app.PendingIntent 20 import android.app.job.JobParameters 21 import android.content.ComponentName 22 import android.content.Context 23 import android.content.ContextWrapper 24 import android.content.Intent 25 import android.content.pm.ApplicationInfo 26 import android.content.pm.PackageInfo 27 import android.os.Build 28 import android.provider.Settings 29 import android.safetycenter.SafetyCenterManager 30 import android.safetycenter.SafetyEvent 31 import android.safetycenter.SafetySourceData 32 import android.safetycenter.SafetySourceIssue 33 import androidx.core.util.Preconditions 34 import androidx.test.core.app.ApplicationProvider 35 import androidx.test.ext.junit.runners.AndroidJUnit4 36 import androidx.test.filters.SdkSuppress 37 import androidx.test.platform.app.InstrumentationRegistry 38 import com.android.dx.mockito.inline.extended.ExtendedMockito 39 import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn 40 import com.android.permissioncontroller.R 41 import com.android.permissioncontroller.permission.utils.Utils 42 import com.android.permissioncontroller.privacysources.DisableNotificationListenerComponentHandler 43 import com.android.permissioncontroller.privacysources.NotificationListenerActionCardDismissalReceiver 44 import com.android.permissioncontroller.privacysources.NotificationListenerCheckInternal 45 import com.android.permissioncontroller.privacysources.NotificationListenerCheckInternal.Companion.NLS_PREFERENCE_FILE 46 import com.android.permissioncontroller.privacysources.NotificationListenerCheckJobService 47 import com.android.permissioncontroller.privacysources.SC_NLS_DISABLE_ACTION_ID 48 import com.android.permissioncontroller.privacysources.SC_NLS_SOURCE_ID 49 import com.google.common.truth.Truth.assertThat 50 import kotlinx.coroutines.runBlocking 51 import org.junit.After 52 import org.junit.Before 53 import org.junit.Test 54 import org.junit.runner.RunWith 55 import org.mockito.ArgumentMatchers.any 56 import org.mockito.ArgumentMatchers.eq 57 import org.mockito.Mock 58 import org.mockito.Mockito.mock 59 import org.mockito.Mockito.verify 60 import org.mockito.MockitoAnnotations 61 import org.mockito.MockitoSession 62 import org.mockito.quality.Strictness 63 64 /** 65 * Unit tests for [NotificationListenerCheckInternal] 66 * 67 * <p> Does not test notification as there are conflicts with being able to mock NotificationManager 68 * and PendintIntent.getBroadcast requiring a valid context. Notifications are tested in the CTS 69 * integration tests 70 */ 71 @RunWith(AndroidJUnit4::class) 72 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu") 73 class NotificationListenerCheckInternalTest { 74 75 @Mock lateinit var mockNotificationListenerCheckJobService: NotificationListenerCheckJobService 76 @Mock lateinit var mockSafetyCenterManager: SafetyCenterManager 77 78 private lateinit var context: Context 79 private lateinit var mockitoSession: MockitoSession 80 private lateinit var notificationListenerCheck: NotificationListenerCheckInternal 81 82 private var shouldCancel = false 83 84 @Before setupnull85 fun setup() { 86 MockitoAnnotations.initMocks(this) 87 context = ApplicationProvider.getApplicationContext() 88 89 mockitoSession = 90 ExtendedMockito.mockitoSession() 91 .spyStatic(Utils::class.java) 92 .strictness(Strictness.LENIENT) 93 .startMocking() 94 95 // Setup Safety Center 96 doReturn(mockSafetyCenterManager).`when` { 97 Utils.getSystemServiceSafe( 98 any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java)) 99 } 100 101 notificationListenerCheck = runWithShellPermissionIdentity { 102 NotificationListenerCheckInternal(context) { shouldCancel } 103 } 104 105 // ensure tests start with clean sharedPrefs 106 clearSharedPrefState() 107 } 108 109 @After cleanupnull110 fun cleanup() { 111 clearSharedPrefState() 112 shouldCancel = false 113 mockitoSession.finishMocking() 114 } 115 116 @Test getEnabledNotificationListenersAndNotifyIfNeeded_shouldCancel_finishJob_reschedulenull117 fun getEnabledNotificationListenersAndNotifyIfNeeded_shouldCancel_finishJob_reschedule() { 118 shouldCancel = true 119 val jobParameters = mock(JobParameters::class.java) 120 121 runWithShellPermissionIdentity { 122 runBlocking { 123 notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded( 124 jobParameters, mockNotificationListenerCheckJobService) 125 } 126 } 127 128 verify(mockNotificationListenerCheckJobService).jobFinished(jobParameters, true) 129 } 130 131 @Test getEnabledNotificationListenersAndNotifyIfNeeded_finishJobnull132 fun getEnabledNotificationListenersAndNotifyIfNeeded_finishJob() { 133 val jobParameters = mock(JobParameters::class.java) 134 135 runWithShellPermissionIdentity { 136 runBlocking { 137 notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded( 138 jobParameters, mockNotificationListenerCheckJobService) 139 } 140 } 141 142 verify(mockNotificationListenerCheckJobService).jobFinished(jobParameters, false) 143 } 144 145 @Test getEnabledNotificationListenersAndNotifyIfNeeded_sendsDataToSafetyCenternull146 fun getEnabledNotificationListenersAndNotifyIfNeeded_sendsDataToSafetyCenter() { 147 val jobParameters = mock(JobParameters::class.java) 148 149 runWithShellPermissionIdentity { 150 runBlocking { 151 notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded( 152 jobParameters, mockNotificationListenerCheckJobService) 153 } 154 } 155 156 verify(mockSafetyCenterManager) 157 .setSafetySourceData( 158 eq(SC_NLS_SOURCE_ID), 159 any(SafetySourceData::class.java), 160 any(SafetyEvent::class.java)) 161 } 162 163 @Test removeDisabledComponentsFromNotifiedComponentsnull164 fun removeDisabledComponentsFromNotifiedComponents() { 165 val testComponent = ComponentName("com.test.package", "TestClass") 166 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 167 val initialEnabledComponents = listOf(testComponent, testComponent2) 168 val updatedEnabledComponents = listOf(testComponent2) 169 170 // Mark all components as notified, and get the resulting list of ComponentNames 171 val initialNlsComponents = runBlocking { 172 initialEnabledComponents.forEach { 173 notificationListenerCheck.markComponentAsNotified(it) 174 } 175 getNotifiedComponents() 176 } 177 178 // Verify expected components are present 179 assertThat(initialNlsComponents).isNotNull() 180 assertThat(initialNlsComponents.size).isEqualTo(initialEnabledComponents.size) 181 initialEnabledComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 182 183 // Forget about test package, and get the resulting list of ComponentNames 184 // Filter to the component that match the test component 185 val updatedNlsComponents = runWithShellPermissionIdentity { 186 runBlocking { 187 notificationListenerCheck.removeDisabledComponentsFromNotifiedComponents( 188 updatedEnabledComponents) 189 getNotifiedComponents() 190 } 191 } 192 193 // Verify expected components are present 194 assertThat(updatedNlsComponents).isNotNull() 195 assertThat(updatedNlsComponents.size).isEqualTo(updatedEnabledComponents.size) 196 updatedEnabledComponents.forEach { assertThat(updatedNlsComponents.contains(it)).isTrue() } 197 } 198 199 @Test markAsNotifiednull200 fun markAsNotified() { 201 val testComponent = ComponentName("com.test.package", "TestClass") 202 203 // Mark as notified, and get the resulting list of ComponentName 204 // Filter to the component that match the test component 205 // Ensure size is equal to one (not empty) 206 runBlocking { 207 notificationListenerCheck.markComponentAsNotified(testComponent) 208 getNotifiedComponents() 209 } 210 .filter { it == testComponent } 211 .also { assertThat(it.size).isEqualTo(1) } 212 } 213 214 @Test markAsNotified_notifySecondComponentnull215 fun markAsNotified_notifySecondComponent() { 216 val testComponent = ComponentName("com.test.package", "TestClass") 217 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 218 219 // Mark as notified, and get the resulting list of ComponentNames 220 var nlsComponents = runBlocking { 221 notificationListenerCheck.markComponentAsNotified(testComponent) 222 getNotifiedComponents() 223 } 224 // Expected # components is 1 225 assertThat(nlsComponents.size).isEqualTo(1) 226 227 // Filter to the component that match the test component 228 // Ensure size is equal to one (not empty) 229 nlsComponents.filter { it == testComponent }.also { assertThat(it.size).isEqualTo(1) } 230 231 // Mark second component as notified, and get the resulting list of ComponentNames 232 nlsComponents = runBlocking { 233 notificationListenerCheck.markComponentAsNotified(testComponent2) 234 getNotifiedComponents() 235 } 236 // Expected # components is 2 237 assertThat(nlsComponents.size).isEqualTo(2) 238 239 // Filter to the component that match the test component 240 // Ensure size is equal to one (not empty) 241 nlsComponents.filter { it == testComponent2 }.also { assertThat(it.size).isEqualTo(1) } 242 } 243 244 @Test markAsNotified_notifySecondComponent_ensureFirstComponentNotModifiednull245 fun markAsNotified_notifySecondComponent_ensureFirstComponentNotModified() { 246 val testComponent = ComponentName("com.test.package", "TestClass") 247 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 248 249 // Mark as notified, and get the resulting list of ComponentNames 250 var nlsComponents = runBlocking { 251 notificationListenerCheck.markComponentAsNotified(testComponent) 252 getNotifiedComponents() 253 } 254 // Expected # components is 1 255 assertThat(nlsComponents.size).isEqualTo(1) 256 257 // Filter to the component that match the test component 258 // Ensure size is equal to one (not empty) 259 // Get the component 260 val firstComponent = 261 nlsComponents 262 .filter { it == testComponent } 263 .also { assertThat(it.size).isEqualTo(1) }[0] 264 265 // Mark second component as notified, and get the resulting list of ComponentNames 266 nlsComponents = runBlocking { 267 notificationListenerCheck.markComponentAsNotified(testComponent2) 268 getNotifiedComponents() 269 } 270 // Expected # components is 2 271 assertThat(nlsComponents.size).isEqualTo(2) 272 273 // Verify first notified component still present 274 assertThat(nlsComponents.contains(firstComponent)).isTrue() 275 } 276 277 @Test removeFromNotifiedComponentsnull278 fun removeFromNotifiedComponents() { 279 val testComponent = ComponentName("com.test.package", "TestClass") 280 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 281 val testComponents = listOf(testComponent, testComponent2) 282 283 // Mark all components as notified, and get the resulting list of ComponentNames 284 val initialNlsComponents = runBlocking { 285 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 286 getNotifiedComponents() 287 } 288 289 // Verify expected components are present 290 assertThat(initialNlsComponents).isNotNull() 291 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 292 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 293 294 // Forget about test package, and get the resulting list of ComponentNames 295 // Filter to the component that match the test component 296 val updatedNlsComponents = runWithShellPermissionIdentity { 297 runBlocking { 298 notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName) 299 getNotifiedComponents() 300 } 301 } 302 303 // Verify expected components are present 304 assertThat(updatedNlsComponents).isNotNull() 305 assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1) 306 assertThat(updatedNlsComponents.contains(testComponent)).isFalse() 307 assertThat(updatedNlsComponents.contains(testComponent2)).isTrue() 308 } 309 310 @Test removeFromNotifiedComponents_multipleNlsPerPackagenull311 fun removeFromNotifiedComponents_multipleNlsPerPackage() { 312 val testComponent = ComponentName("com.test.package", "TestClass") 313 val testComponent2 = ComponentName("com.test.package", "TestClass2") 314 val testComponents = listOf(testComponent, testComponent2) 315 316 // Mark all components as notified, and get the resulting list of ComponentNames 317 val initialNlsComponents = runBlocking { 318 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 319 getNotifiedComponents() 320 } 321 322 // Verify expected components are present 323 assertThat(initialNlsComponents).isNotNull() 324 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 325 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 326 327 // Forget about test package, and get the resulting list of ComponentNames 328 // Filter to the component that match the test component 329 val updatedNlsComponents = runWithShellPermissionIdentity { 330 runBlocking { 331 notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName) 332 getNotifiedComponents() 333 } 334 } 335 336 // Ensure empty 337 assertThat(updatedNlsComponents).isEmpty() 338 } 339 340 @Test removeFromNotifiedComponents_noPreviouslyNotifiedPackagenull341 fun removeFromNotifiedComponents_noPreviouslyNotifiedPackage() { 342 val testComponent = ComponentName("com.test.package", "TestClass") 343 344 // Forget about test package, and get the resulting list of ComponentNames 345 // Filter to the component that match the test component 346 val updatedNlsComponents = runWithShellPermissionIdentity { 347 runBlocking { 348 // Verify this should not fail! 349 notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName) 350 getNotifiedComponents() 351 } 352 } 353 354 // Verify no components are present 355 assertThat(updatedNlsComponents).isEmpty() 356 } 357 358 @Test removeFromNotifiedComponents_componentNamenull359 fun removeFromNotifiedComponents_componentName() { 360 val testComponent = ComponentName("com.test.package", "TestClass") 361 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 362 val testComponents = listOf(testComponent, testComponent2) 363 364 // Mark all components as notified, and get the resulting list of ComponentNames 365 val initialNlsComponents = runBlocking { 366 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 367 getNotifiedComponents() 368 } 369 370 // Verify expected components are present 371 assertThat(initialNlsComponents).isNotNull() 372 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 373 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 374 375 // Forget about test component, and get the resulting list of ComponentNames 376 // Filter to the component that match the test component 377 val updatedNlsComponents = runWithShellPermissionIdentity { 378 runBlocking { 379 notificationListenerCheck.removeFromNotifiedComponents(testComponent) 380 getNotifiedComponents() 381 } 382 } 383 384 // Verify expected components are present 385 assertThat(updatedNlsComponents).isNotNull() 386 assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1) 387 assertThat(updatedNlsComponents.contains(testComponent)).isFalse() 388 assertThat(updatedNlsComponents.contains(testComponent2)).isTrue() 389 } 390 391 @Test removeFromNotifiedComponents_componentName_multipleNlsPerPackagenull392 fun removeFromNotifiedComponents_componentName_multipleNlsPerPackage() { 393 val testComponent = ComponentName("com.test.package", "TestClass") 394 val testComponent2 = ComponentName("com.test.package", "TestClass2") 395 val testComponents = listOf(testComponent, testComponent2) 396 397 // Mark all components as notified, and get the resulting list of ComponentNames 398 val initialNlsComponents = runBlocking { 399 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 400 getNotifiedComponents() 401 } 402 403 // Verify expected components are present 404 assertThat(initialNlsComponents).isNotNull() 405 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 406 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 407 408 // Forget about test component, and get the resulting list of ComponentNames 409 // Filter to the component that match the test component 410 val updatedNlsComponents = runWithShellPermissionIdentity { 411 runBlocking { 412 notificationListenerCheck.removeFromNotifiedComponents(testComponent) 413 getNotifiedComponents() 414 } 415 } 416 417 // Verify expected components are present 418 assertThat(updatedNlsComponents).isNotNull() 419 assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1) 420 assertThat(updatedNlsComponents.contains(testComponent)).isFalse() 421 assertThat(updatedNlsComponents.contains(testComponent2)).isTrue() 422 } 423 424 @Test removeFromNotifiedComponents_componentName_noPreviouslyNotifiedPackagenull425 fun removeFromNotifiedComponents_componentName_noPreviouslyNotifiedPackage() { 426 val testComponent = ComponentName("com.test.package", "TestClass") 427 428 // Forget about test component, and get the resulting list of ComponentNames 429 // Filter to the component that match the test component 430 val updatedNlsComponents = runWithShellPermissionIdentity { 431 runBlocking { 432 // Verify this should not fail! 433 notificationListenerCheck.removeFromNotifiedComponents(testComponent) 434 getNotifiedComponents() 435 } 436 } 437 438 // Verify no components are present 439 assertThat(updatedNlsComponents).isEmpty() 440 } 441 442 @Test createSafetySourceIssuenull443 fun createSafetySourceIssue() { 444 val testComponent = ComponentName("com.test.package", "TestClass") 445 val testAppLabel = "TestApp Label" 446 doReturn(PackageInfo().apply { applicationInfo = ApplicationInfo() }).`when` { 447 Utils.getPackageInfoForComponentName( 448 any(Context::class.java), any(ComponentName::class.java)) 449 } 450 doReturn(testAppLabel).`when` { 451 Utils.getApplicationLabel(any(Context::class.java), any(ApplicationInfo::class.java)) 452 } 453 454 val safetySourceIssue = 455 Preconditions.checkNotNull( 456 notificationListenerCheck.createSafetySourceIssue(testComponent, 0)) 457 458 val expectedId = "notification_listener_${testComponent.flattenToString()}" 459 val expectedTitle = 460 context.getString(R.string.notification_listener_reminder_notification_title) 461 val expectedSubtitle: String = testAppLabel.toString() 462 val expectedSummary = context.getString(R.string.notification_listener_warning_card_content) 463 val expectedSeverityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION 464 val expectedIssueTypeId = NotificationListenerCheckInternal.SC_NLS_ISSUE_TYPE_ID 465 val expectedDismissIntent = 466 Intent(context, NotificationListenerActionCardDismissalReceiver::class.java).apply { 467 putExtra(Intent.EXTRA_COMPONENT_NAME, testComponent) 468 flags = Intent.FLAG_RECEIVER_FOREGROUND 469 identifier = testComponent.flattenToString() 470 } 471 val expectedDismissPendingIntent = 472 PendingIntent.getBroadcast( 473 context, 0, expectedDismissIntent, PendingIntent.FLAG_IMMUTABLE) 474 val expectedAction1 = 475 SafetySourceIssue.Action.Builder( 476 SC_NLS_DISABLE_ACTION_ID, 477 context.getString(R.string.notification_listener_remove_access_button_label), 478 getDisableNlsPendingIntent(context, expectedId, testComponent)) 479 .setWillResolve(true) 480 .setSuccessMessage( 481 context.getString(R.string.notification_listener_remove_access_success_label)) 482 .build() 483 val expectedAction2 = 484 SafetySourceIssue.Action.Builder( 485 NotificationListenerCheckInternal.SC_SHOW_NLS_SETTINGS_ACTION_ID, 486 context.getString(R.string.notification_listener_review_app_button_label), 487 getNotificationListenerSettingsPendingIntent(context, testComponent)) 488 .build() 489 490 assertThat(safetySourceIssue.id).isEqualTo(expectedId) 491 assertThat(safetySourceIssue.title).isEqualTo(expectedTitle) 492 assertThat(safetySourceIssue.subtitle).isEqualTo(expectedSubtitle) 493 assertThat(safetySourceIssue.summary).isEqualTo(expectedSummary) 494 assertThat(safetySourceIssue.severityLevel).isEqualTo(expectedSeverityLevel) 495 assertThat(safetySourceIssue.issueTypeId).isEqualTo(expectedIssueTypeId) 496 assertThat(safetySourceIssue.onDismissPendingIntent).isEqualTo(expectedDismissPendingIntent) 497 assertThat(safetySourceIssue.actions.size).isEqualTo(2) 498 assertThat(safetySourceIssue.actions).containsExactly(expectedAction2, expectedAction1) 499 } 500 501 @Test exemptPackagesNotInitializedUntilUsednull502 fun exemptPackagesNotInitializedUntilUsed() { 503 assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isFalse() 504 runWithShellPermissionIdentity { 505 notificationListenerCheck.exemptPackages 506 } 507 assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isTrue() 508 } 509 <lambda>null510 private fun getNotifiedComponents(): Set<ComponentName> = runBlocking { 511 notificationListenerCheck 512 .getNotifiedComponents() 513 .mapNotNull { ComponentName.unflattenFromString(it) } 514 .toSet() 515 } 516 517 /** @return [PendingIntent] for remove access button on the warning card. */ getDisableNlsPendingIntentnull518 private fun getDisableNlsPendingIntent( 519 context: Context, 520 safetySourceIssueId: String, 521 componentName: ComponentName 522 ): PendingIntent { 523 val intent = 524 Intent(context, DisableNotificationListenerComponentHandler::class.java).apply { 525 putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID, safetySourceIssueId) 526 putExtra(Intent.EXTRA_COMPONENT_NAME, componentName) 527 flags = Intent.FLAG_RECEIVER_FOREGROUND 528 identifier = componentName.flattenToString() 529 } 530 531 return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) 532 } 533 534 /** @return [PendingIntent] to Notification Listener Settings page */ getNotificationListenerSettingsPendingIntentnull535 private fun getNotificationListenerSettingsPendingIntent( 536 context: Context, 537 componentName: ComponentName 538 ): PendingIntent { 539 val intent = 540 Intent(Settings.ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS).apply { 541 flags = Intent.FLAG_ACTIVITY_NEW_TASK 542 identifier = componentName.flattenToString() 543 putExtra( 544 Settings.EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME, 545 componentName.flattenToString()) 546 } 547 return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) 548 } 549 clearSharedPrefStatenull550 private fun clearSharedPrefState() { 551 context 552 .getSharedPreferences(NLS_PREFERENCE_FILE, Context.MODE_PRIVATE) 553 .edit() 554 .clear() 555 .apply() 556 } 557 runWithShellPermissionIdentitynull558 private fun <R> runWithShellPermissionIdentity(block: () -> R): R { 559 val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation() 560 uiAutomation.adoptShellPermissionIdentity() 561 try { 562 return block() 563 } finally { 564 uiAutomation.dropShellPermissionIdentity() 565 } 566 } 567 } 568