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), 99 eq(SafetyCenterManager::class.java) 100 ) 101 } 102 103 notificationListenerCheck = runWithShellPermissionIdentity { 104 NotificationListenerCheckInternal(context) { shouldCancel } 105 } 106 107 // ensure tests start with clean sharedPrefs 108 clearSharedPrefState() 109 } 110 111 @After cleanupnull112 fun cleanup() { 113 clearSharedPrefState() 114 shouldCancel = false 115 mockitoSession.finishMocking() 116 } 117 118 @Test getEnabledNotificationListenersAndNotifyIfNeeded_shouldCancel_finishJob_reschedulenull119 fun getEnabledNotificationListenersAndNotifyIfNeeded_shouldCancel_finishJob_reschedule() { 120 shouldCancel = true 121 val jobParameters = mock(JobParameters::class.java) 122 123 runWithShellPermissionIdentity { 124 runBlocking { 125 notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded( 126 jobParameters, 127 mockNotificationListenerCheckJobService 128 ) 129 } 130 } 131 132 verify(mockNotificationListenerCheckJobService).jobFinished(jobParameters, true) 133 } 134 135 @Test getEnabledNotificationListenersAndNotifyIfNeeded_finishJobnull136 fun getEnabledNotificationListenersAndNotifyIfNeeded_finishJob() { 137 val jobParameters = mock(JobParameters::class.java) 138 139 runWithShellPermissionIdentity { 140 runBlocking { 141 notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded( 142 jobParameters, 143 mockNotificationListenerCheckJobService 144 ) 145 } 146 } 147 148 verify(mockNotificationListenerCheckJobService).jobFinished(jobParameters, false) 149 } 150 151 @Test getEnabledNotificationListenersAndNotifyIfNeeded_sendsDataToSafetyCenternull152 fun getEnabledNotificationListenersAndNotifyIfNeeded_sendsDataToSafetyCenter() { 153 val jobParameters = mock(JobParameters::class.java) 154 155 runWithShellPermissionIdentity { 156 runBlocking { 157 notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded( 158 jobParameters, 159 mockNotificationListenerCheckJobService 160 ) 161 } 162 } 163 164 verify(mockSafetyCenterManager) 165 .setSafetySourceData( 166 eq(SC_NLS_SOURCE_ID), 167 any(SafetySourceData::class.java), 168 any(SafetyEvent::class.java) 169 ) 170 } 171 172 @Test removeDisabledComponentsFromNotifiedComponentsnull173 fun removeDisabledComponentsFromNotifiedComponents() { 174 val testComponent = ComponentName("com.test.package", "TestClass") 175 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 176 val initialEnabledComponents = listOf(testComponent, testComponent2) 177 val updatedEnabledComponents = listOf(testComponent2) 178 179 // Mark all components as notified, and get the resulting list of ComponentNames 180 val initialNlsComponents = runBlocking { 181 initialEnabledComponents.forEach { 182 notificationListenerCheck.markComponentAsNotified(it) 183 } 184 getNotifiedComponents() 185 } 186 187 // Verify expected components are present 188 assertThat(initialNlsComponents).isNotNull() 189 assertThat(initialNlsComponents.size).isEqualTo(initialEnabledComponents.size) 190 initialEnabledComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 191 192 // Forget about test package, and get the resulting list of ComponentNames 193 // Filter to the component that match the test component 194 val updatedNlsComponents = runWithShellPermissionIdentity { 195 runBlocking { 196 notificationListenerCheck.removeDisabledComponentsFromNotifiedComponents( 197 updatedEnabledComponents 198 ) 199 getNotifiedComponents() 200 } 201 } 202 203 // Verify expected components are present 204 assertThat(updatedNlsComponents).isNotNull() 205 assertThat(updatedNlsComponents.size).isEqualTo(updatedEnabledComponents.size) 206 updatedEnabledComponents.forEach { assertThat(updatedNlsComponents.contains(it)).isTrue() } 207 } 208 209 @Test markAsNotifiednull210 fun markAsNotified() { 211 val testComponent = ComponentName("com.test.package", "TestClass") 212 213 // Mark as notified, and get the resulting list of ComponentName 214 // Filter to the component that match the test component 215 // Ensure size is equal to one (not empty) 216 runBlocking { 217 notificationListenerCheck.markComponentAsNotified(testComponent) 218 getNotifiedComponents() 219 } 220 .filter { it == testComponent } 221 .also { assertThat(it.size).isEqualTo(1) } 222 } 223 224 @Test markAsNotified_notifySecondComponentnull225 fun markAsNotified_notifySecondComponent() { 226 val testComponent = ComponentName("com.test.package", "TestClass") 227 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 228 229 // Mark as notified, and get the resulting list of ComponentNames 230 var nlsComponents = runBlocking { 231 notificationListenerCheck.markComponentAsNotified(testComponent) 232 getNotifiedComponents() 233 } 234 // Expected # components is 1 235 assertThat(nlsComponents.size).isEqualTo(1) 236 237 // Filter to the component that match the test component 238 // Ensure size is equal to one (not empty) 239 nlsComponents.filter { it == testComponent }.also { assertThat(it.size).isEqualTo(1) } 240 241 // Mark second component as notified, and get the resulting list of ComponentNames 242 nlsComponents = runBlocking { 243 notificationListenerCheck.markComponentAsNotified(testComponent2) 244 getNotifiedComponents() 245 } 246 // Expected # components is 2 247 assertThat(nlsComponents.size).isEqualTo(2) 248 249 // Filter to the component that match the test component 250 // Ensure size is equal to one (not empty) 251 nlsComponents.filter { it == testComponent2 }.also { assertThat(it.size).isEqualTo(1) } 252 } 253 254 @Test markAsNotified_notifySecondComponent_ensureFirstComponentNotModifiednull255 fun markAsNotified_notifySecondComponent_ensureFirstComponentNotModified() { 256 val testComponent = ComponentName("com.test.package", "TestClass") 257 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 258 259 // Mark as notified, and get the resulting list of ComponentNames 260 var nlsComponents = runBlocking { 261 notificationListenerCheck.markComponentAsNotified(testComponent) 262 getNotifiedComponents() 263 } 264 // Expected # components is 1 265 assertThat(nlsComponents.size).isEqualTo(1) 266 267 // Filter to the component that match the test component 268 // Ensure size is equal to one (not empty) 269 // Get the component 270 val firstComponent = 271 nlsComponents 272 .filter { it == testComponent } 273 .also { assertThat(it.size).isEqualTo(1) }[0] 274 275 // Mark second component as notified, and get the resulting list of ComponentNames 276 nlsComponents = runBlocking { 277 notificationListenerCheck.markComponentAsNotified(testComponent2) 278 getNotifiedComponents() 279 } 280 // Expected # components is 2 281 assertThat(nlsComponents.size).isEqualTo(2) 282 283 // Verify first notified component still present 284 assertThat(nlsComponents.contains(firstComponent)).isTrue() 285 } 286 287 @Test removeFromNotifiedComponentsnull288 fun removeFromNotifiedComponents() { 289 val testComponent = ComponentName("com.test.package", "TestClass") 290 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 291 val testComponents = listOf(testComponent, testComponent2) 292 293 // Mark all components as notified, and get the resulting list of ComponentNames 294 val initialNlsComponents = runBlocking { 295 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 296 getNotifiedComponents() 297 } 298 299 // Verify expected components are present 300 assertThat(initialNlsComponents).isNotNull() 301 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 302 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 303 304 // Forget about test package, and get the resulting list of ComponentNames 305 // Filter to the component that match the test component 306 val updatedNlsComponents = runWithShellPermissionIdentity { 307 runBlocking { 308 notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName) 309 getNotifiedComponents() 310 } 311 } 312 313 // Verify expected components are present 314 assertThat(updatedNlsComponents).isNotNull() 315 assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1) 316 assertThat(updatedNlsComponents.contains(testComponent)).isFalse() 317 assertThat(updatedNlsComponents.contains(testComponent2)).isTrue() 318 } 319 320 @Test removeFromNotifiedComponents_multipleNlsPerPackagenull321 fun removeFromNotifiedComponents_multipleNlsPerPackage() { 322 val testComponent = ComponentName("com.test.package", "TestClass") 323 val testComponent2 = ComponentName("com.test.package", "TestClass2") 324 val testComponents = listOf(testComponent, testComponent2) 325 326 // Mark all components as notified, and get the resulting list of ComponentNames 327 val initialNlsComponents = runBlocking { 328 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 329 getNotifiedComponents() 330 } 331 332 // Verify expected components are present 333 assertThat(initialNlsComponents).isNotNull() 334 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 335 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 336 337 // Forget about test package, and get the resulting list of ComponentNames 338 // Filter to the component that match the test component 339 val updatedNlsComponents = runWithShellPermissionIdentity { 340 runBlocking { 341 notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName) 342 getNotifiedComponents() 343 } 344 } 345 346 // Ensure empty 347 assertThat(updatedNlsComponents).isEmpty() 348 } 349 350 @Test removeFromNotifiedComponents_noPreviouslyNotifiedPackagenull351 fun removeFromNotifiedComponents_noPreviouslyNotifiedPackage() { 352 val testComponent = ComponentName("com.test.package", "TestClass") 353 354 // Forget about test package, and get the resulting list of ComponentNames 355 // Filter to the component that match the test component 356 val updatedNlsComponents = runWithShellPermissionIdentity { 357 runBlocking { 358 // Verify this should not fail! 359 notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName) 360 getNotifiedComponents() 361 } 362 } 363 364 // Verify no components are present 365 assertThat(updatedNlsComponents).isEmpty() 366 } 367 368 @Test removeFromNotifiedComponents_componentNamenull369 fun removeFromNotifiedComponents_componentName() { 370 val testComponent = ComponentName("com.test.package", "TestClass") 371 val testComponent2 = ComponentName("com.test.package2", "TestClass2") 372 val testComponents = listOf(testComponent, testComponent2) 373 374 // Mark all components as notified, and get the resulting list of ComponentNames 375 val initialNlsComponents = runBlocking { 376 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 377 getNotifiedComponents() 378 } 379 380 // Verify expected components are present 381 assertThat(initialNlsComponents).isNotNull() 382 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 383 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 384 385 // Forget about test component, and get the resulting list of ComponentNames 386 // Filter to the component that match the test component 387 val updatedNlsComponents = runWithShellPermissionIdentity { 388 runBlocking { 389 notificationListenerCheck.removeFromNotifiedComponents(testComponent) 390 getNotifiedComponents() 391 } 392 } 393 394 // Verify expected components are present 395 assertThat(updatedNlsComponents).isNotNull() 396 assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1) 397 assertThat(updatedNlsComponents.contains(testComponent)).isFalse() 398 assertThat(updatedNlsComponents.contains(testComponent2)).isTrue() 399 } 400 401 @Test removeFromNotifiedComponents_componentName_multipleNlsPerPackagenull402 fun removeFromNotifiedComponents_componentName_multipleNlsPerPackage() { 403 val testComponent = ComponentName("com.test.package", "TestClass") 404 val testComponent2 = ComponentName("com.test.package", "TestClass2") 405 val testComponents = listOf(testComponent, testComponent2) 406 407 // Mark all components as notified, and get the resulting list of ComponentNames 408 val initialNlsComponents = runBlocking { 409 testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) } 410 getNotifiedComponents() 411 } 412 413 // Verify expected components are present 414 assertThat(initialNlsComponents).isNotNull() 415 assertThat(initialNlsComponents.size).isEqualTo(testComponents.size) 416 testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() } 417 418 // Forget about test component, and get the resulting list of ComponentNames 419 // Filter to the component that match the test component 420 val updatedNlsComponents = runWithShellPermissionIdentity { 421 runBlocking { 422 notificationListenerCheck.removeFromNotifiedComponents(testComponent) 423 getNotifiedComponents() 424 } 425 } 426 427 // Verify expected components are present 428 assertThat(updatedNlsComponents).isNotNull() 429 assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1) 430 assertThat(updatedNlsComponents.contains(testComponent)).isFalse() 431 assertThat(updatedNlsComponents.contains(testComponent2)).isTrue() 432 } 433 434 @Test removeFromNotifiedComponents_componentName_noPreviouslyNotifiedPackagenull435 fun removeFromNotifiedComponents_componentName_noPreviouslyNotifiedPackage() { 436 val testComponent = ComponentName("com.test.package", "TestClass") 437 438 // Forget about test component, and get the resulting list of ComponentNames 439 // Filter to the component that match the test component 440 val updatedNlsComponents = runWithShellPermissionIdentity { 441 runBlocking { 442 // Verify this should not fail! 443 notificationListenerCheck.removeFromNotifiedComponents(testComponent) 444 getNotifiedComponents() 445 } 446 } 447 448 // Verify no components are present 449 assertThat(updatedNlsComponents).isEmpty() 450 } 451 452 @Test createSafetySourceIssuenull453 fun createSafetySourceIssue() { 454 val testComponent = ComponentName("com.test.package", "TestClass") 455 val testAppLabel = "TestApp Label" 456 doReturn(PackageInfo().apply { applicationInfo = ApplicationInfo() }).`when` { 457 Utils.getPackageInfoForComponentName( 458 any(Context::class.java), 459 any(ComponentName::class.java) 460 ) 461 } 462 doReturn(testAppLabel).`when` { 463 Utils.getApplicationLabel(any(Context::class.java), any(ApplicationInfo::class.java)) 464 } 465 466 val safetySourceIssue = 467 Preconditions.checkNotNull( 468 notificationListenerCheck.createSafetySourceIssue(testComponent, 0) 469 ) 470 471 val expectedId = "notification_listener_${testComponent.flattenToString()}" 472 val expectedTitle = 473 context.getString(R.string.notification_listener_reminder_notification_title) 474 val expectedSubtitle: String = testAppLabel.toString() 475 val expectedSummary = context.getString(R.string.notification_listener_warning_card_content) 476 val expectedSeverityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION 477 val expectedIssueTypeId = NotificationListenerCheckInternal.SC_NLS_ISSUE_TYPE_ID 478 val expectedDismissIntent = 479 Intent(context, NotificationListenerActionCardDismissalReceiver::class.java).apply { 480 putExtra(Intent.EXTRA_COMPONENT_NAME, testComponent) 481 flags = Intent.FLAG_RECEIVER_FOREGROUND 482 identifier = testComponent.flattenToString() 483 } 484 val expectedDismissPendingIntent = 485 PendingIntent.getBroadcast( 486 context, 487 0, 488 expectedDismissIntent, 489 PendingIntent.FLAG_IMMUTABLE 490 ) 491 val expectedAction1 = 492 SafetySourceIssue.Action.Builder( 493 SC_NLS_DISABLE_ACTION_ID, 494 context.getString(R.string.notification_listener_remove_access_button_label), 495 getDisableNlsPendingIntent(context, expectedId, testComponent) 496 ) 497 .setWillResolve(true) 498 .setSuccessMessage( 499 context.getString(R.string.notification_listener_remove_access_success_label) 500 ) 501 .build() 502 val expectedAction2 = 503 SafetySourceIssue.Action.Builder( 504 NotificationListenerCheckInternal.SC_SHOW_NLS_SETTINGS_ACTION_ID, 505 context.getString(R.string.notification_listener_review_app_button_label), 506 getNotificationListenerSettingsPendingIntent(context, testComponent) 507 ) 508 .build() 509 510 assertThat(safetySourceIssue.id).isEqualTo(expectedId) 511 assertThat(safetySourceIssue.title).isEqualTo(expectedTitle) 512 assertThat(safetySourceIssue.subtitle).isEqualTo(expectedSubtitle) 513 assertThat(safetySourceIssue.summary).isEqualTo(expectedSummary) 514 assertThat(safetySourceIssue.severityLevel).isEqualTo(expectedSeverityLevel) 515 assertThat(safetySourceIssue.issueTypeId).isEqualTo(expectedIssueTypeId) 516 assertThat(safetySourceIssue.onDismissPendingIntent).isEqualTo(expectedDismissPendingIntent) 517 assertThat(safetySourceIssue.actions.size).isEqualTo(2) 518 assertThat(safetySourceIssue.actions).containsExactly(expectedAction2, expectedAction1) 519 } 520 521 @Test exemptPackagesNotInitializedUntilUsednull522 fun exemptPackagesNotInitializedUntilUsed() { 523 assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isFalse() 524 runWithShellPermissionIdentity { notificationListenerCheck.exemptPackages } 525 assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isTrue() 526 } 527 <lambda>null528 private fun getNotifiedComponents(): Set<ComponentName> = runBlocking { 529 notificationListenerCheck 530 .getNotifiedComponents() 531 .mapNotNull { ComponentName.unflattenFromString(it) } 532 .toSet() 533 } 534 535 /** @return [PendingIntent] for remove access button on the warning card. */ getDisableNlsPendingIntentnull536 private fun getDisableNlsPendingIntent( 537 context: Context, 538 safetySourceIssueId: String, 539 componentName: ComponentName 540 ): PendingIntent { 541 val intent = 542 Intent(context, DisableNotificationListenerComponentHandler::class.java).apply { 543 putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID, safetySourceIssueId) 544 putExtra(Intent.EXTRA_COMPONENT_NAME, componentName) 545 flags = Intent.FLAG_RECEIVER_FOREGROUND 546 identifier = componentName.flattenToString() 547 } 548 549 return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) 550 } 551 552 /** @return [PendingIntent] to Notification Listener Settings page */ getNotificationListenerSettingsPendingIntentnull553 private fun getNotificationListenerSettingsPendingIntent( 554 context: Context, 555 componentName: ComponentName 556 ): PendingIntent { 557 val intent = 558 Intent(Settings.ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS).apply { 559 flags = Intent.FLAG_ACTIVITY_NEW_TASK 560 identifier = componentName.flattenToString() 561 putExtra( 562 Settings.EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME, 563 componentName.flattenToString() 564 ) 565 } 566 return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) 567 } 568 clearSharedPrefStatenull569 private fun clearSharedPrefState() { 570 context 571 .getSharedPreferences(NLS_PREFERENCE_FILE, Context.MODE_PRIVATE) 572 .edit() 573 .clear() 574 .apply() 575 } 576 runWithShellPermissionIdentitynull577 private fun <R> runWithShellPermissionIdentity(block: () -> R): R { 578 val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation() 579 uiAutomation.adoptShellPermissionIdentity() 580 try { 581 return block() 582 } finally { 583 uiAutomation.dropShellPermissionIdentity() 584 } 585 } 586 } 587