1 /* 2 * Copyright (C) 2019 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.server.notification; 18 19 import static android.app.role.RoleManager.ROLE_BROWSER; 20 import static android.app.role.RoleManager.ROLE_DIALER; 21 import static android.app.role.RoleManager.ROLE_EMERGENCY; 22 import static android.content.pm.PackageManager.MATCH_ALL; 23 24 import static junit.framework.Assert.assertFalse; 25 import static junit.framework.Assert.assertTrue; 26 27 import static org.mockito.ArgumentMatchers.anyBoolean; 28 import static org.mockito.Matchers.eq; 29 import static org.mockito.Mockito.any; 30 import static org.mockito.Mockito.mock; 31 import static org.mockito.Mockito.times; 32 import static org.mockito.Mockito.verify; 33 import static org.mockito.Mockito.when; 34 35 import static java.util.Arrays.asList; 36 37 import android.app.ActivityManager; 38 import android.app.ActivityManagerInternal; 39 import android.app.AppOpsManager; 40 import android.app.IActivityManager; 41 import android.app.IUriGrantsManager; 42 import android.app.StatsManager; 43 import android.app.admin.DevicePolicyManagerInternal; 44 import android.app.role.RoleManager; 45 import android.app.usage.UsageStatsManagerInternal; 46 import android.companion.ICompanionDeviceManager; 47 import android.content.Context; 48 import android.content.pm.IPackageManager; 49 import android.content.pm.PackageManager; 50 import android.os.Looper; 51 import android.os.PowerManager; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 import android.permission.PermissionManager; 55 import android.telecom.TelecomManager; 56 import android.telephony.TelephonyManager; 57 import android.test.suitebuilder.annotation.SmallTest; 58 import android.testing.AndroidTestingRunner; 59 import android.testing.TestableLooper; 60 import android.testing.TestableLooper.RunWithLooper; 61 import android.util.ArraySet; 62 import android.util.AtomicFile; 63 import android.util.Pair; 64 65 import androidx.test.InstrumentationRegistry; 66 67 import com.android.internal.config.sysui.TestableFlagResolver; 68 import com.android.internal.logging.InstanceIdSequence; 69 import com.android.internal.logging.InstanceIdSequenceFake; 70 import com.android.server.LocalServices; 71 import com.android.server.UiServiceTestCase; 72 import com.android.server.lights.LightsManager; 73 import com.android.server.notification.NotificationManagerService.NotificationAssistants; 74 import com.android.server.notification.NotificationManagerService.NotificationListeners; 75 import com.android.server.uri.UriGrantsManagerInternal; 76 import com.android.server.utils.quota.MultiRateLimiter; 77 import com.android.server.wm.ActivityTaskManagerInternal; 78 import com.android.server.wm.WindowManagerInternal; 79 80 import org.junit.After; 81 import org.junit.Before; 82 import org.junit.Test; 83 import org.junit.runner.RunWith; 84 import org.mockito.Mock; 85 import org.mockito.MockitoAnnotations; 86 87 import java.util.ArrayList; 88 import java.util.List; 89 90 @SmallTest 91 @RunWith(AndroidTestingRunner.class) 92 @RunWithLooper 93 // TODO (b/194833441): remove when notification permission is enabled 94 public class RoleObserverTest extends UiServiceTestCase { 95 private TestableNotificationManagerService mService; 96 private NotificationManagerService.RoleObserver mRoleObserver; 97 98 @Mock 99 private PreferencesHelper mPreferencesHelper; 100 @Mock 101 private IPackageManager mPm; 102 @Mock 103 private UserManager mUm; 104 @Mock 105 private RoleManager mRoleManager; 106 @Mock 107 private Looper mMainLooper; 108 private TestableLooper mTestableLooper; 109 NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); 110 private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( 111 1 << 30); 112 private List<UserHandle> mUsers; 113 114 private static class TestableNotificationManagerService extends NotificationManagerService { TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence)115 TestableNotificationManagerService(Context context, 116 NotificationRecordLogger logger, 117 InstanceIdSequence notificationInstanceIdSequence) { 118 super(context, logger, notificationInstanceIdSequence); 119 } 120 121 @Override handleSavePolicyFile()122 protected void handleSavePolicyFile() { } 123 124 @Override loadPolicyFile()125 protected void loadPolicyFile() { } 126 } 127 128 @Before setUp()129 public void setUp() throws Exception { 130 MockitoAnnotations.initMocks(this); 131 // Shell permisssions will override permissions of our app, so add all necessary permissions 132 // for this test here: 133 InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 134 "android.permission.READ_CONTACTS"); 135 136 LocalServices.removeServiceForTest(WindowManagerInternal.class); 137 LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class)); 138 mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); 139 140 mUsers = new ArrayList<>(); 141 mUsers.add(new UserHandle(0)); 142 mUsers.add(new UserHandle(10)); 143 when(mUm.getUserHandles(anyBoolean())).thenReturn(mUsers); 144 145 when(mMainLooper.isCurrentThread()).thenReturn(true); 146 147 mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, 148 mNotificationInstanceIdSequence); 149 mRoleObserver = mService.new RoleObserver(mContext, mRoleManager, mPm, mMainLooper); 150 mTestableLooper = TestableLooper.get(this); 151 152 try { 153 mService.init(mService.new WorkerHandler(mTestableLooper.getLooper()), 154 mock(RankingHandler.class), 155 mock(IPackageManager.class), mock(PackageManager.class), 156 mock(LightsManager.class), 157 mock(NotificationListeners.class), mock(NotificationAssistants.class), 158 mock(ConditionProviders.class), mock(ICompanionDeviceManager.class), 159 mock(SnoozeHelper.class), mock(NotificationUsageStats.class), 160 mock(AtomicFile.class), mock(ActivityManager.class), 161 mock(GroupHelper.class), mock(IActivityManager.class), 162 mock(ActivityTaskManagerInternal.class), 163 mock(UsageStatsManagerInternal.class), 164 mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class), 165 mock(UriGrantsManagerInternal.class), 166 mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class), 167 mock(StatsManager.class), mock(TelephonyManager.class), 168 mock(ActivityManagerInternal.class), 169 mock(MultiRateLimiter.class), mock(PermissionHelper.class), 170 mock(UsageStatsManagerInternal.class), mock(TelecomManager.class), 171 mock(NotificationChannelLogger.class), new TestableFlagResolver(), 172 mock(PermissionManager.class), 173 mock(PowerManager.class), 174 new NotificationManagerService.PostNotificationTrackerFactory() {}); 175 } catch (SecurityException e) { 176 if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) { 177 throw e; 178 } 179 } 180 mService.setPreferencesHelper(mPreferencesHelper); 181 } 182 183 @After tearDown()184 public void tearDown() { 185 InstrumentationRegistry.getInstrumentation() 186 .getUiAutomation().dropShellPermissionIdentity(); 187 } 188 189 @Test testInit_forNonBlockableDefaultApps()190 public void testInit_forNonBlockableDefaultApps() throws Exception { 191 List<String> dialer0 = new ArrayList<>(); 192 dialer0.add("dialer"); 193 List<String> emer0 = new ArrayList<>(); 194 emer0.add("emergency"); 195 196 ArraySet<Pair<String, Integer>> dialer0Pair = new ArraySet<>(); 197 dialer0Pair.add(new Pair("dialer", 30)); 198 when(mPm.getPackageUid("dialer", MATCH_ALL, 0)).thenReturn(30); 199 200 ArraySet<Pair<String, Integer>> emer0Pair = new ArraySet<>(); 201 emer0Pair.add(new Pair("emergency", 40)); 202 when(mPm.getPackageUid("emergency", MATCH_ALL, 0)).thenReturn(40); 203 204 205 when(mRoleManager.getRoleHoldersAsUser( 206 ROLE_DIALER, 207 mUsers.get(0))) 208 .thenReturn(dialer0); 209 when(mRoleManager.getRoleHoldersAsUser( 210 ROLE_EMERGENCY, 211 mUsers.get(0))) 212 .thenReturn(emer0); 213 214 mRoleObserver.init(); 215 216 // verify internal records of current state of the world 217 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser( 218 ROLE_DIALER, dialer0.get(0), mUsers.get(0).getIdentifier())); 219 assertFalse(mRoleObserver.isApprovedPackageForRoleForUser( 220 ROLE_DIALER, dialer0.get(0), mUsers.get(1).getIdentifier())); 221 222 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser( 223 ROLE_EMERGENCY, emer0.get(0), mUsers.get(0).getIdentifier())); 224 assertFalse(mRoleObserver.isApprovedPackageForRoleForUser( 225 ROLE_EMERGENCY, emer0.get(0), mUsers.get(1).getIdentifier())); 226 227 // make sure we're listening to updates 228 verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser( 229 any(), any(), eq(UserHandle.ALL)); 230 231 // make sure we told pref helper about the state of the world 232 verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, dialer0Pair); 233 verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, emer0Pair); 234 } 235 236 @Test testInit_forTrampolines()237 public void testInit_forTrampolines() throws Exception { 238 when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30); 239 when(mRoleManager.getRoleHoldersAsUser( 240 ROLE_BROWSER, 241 mUsers.get(0))) 242 .thenReturn(asList("com.browser")); 243 244 mRoleObserver.init(); 245 246 assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); 247 248 // make sure we're listening to updates 249 verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser(any(), any(), 250 eq(UserHandle.ALL)); 251 } 252 253 @Test testSwapDefault_forNonBlockableDefaultApps()254 public void testSwapDefault_forNonBlockableDefaultApps() throws Exception { 255 List<String> dialer0 = new ArrayList<>(); 256 dialer0.add("dialer"); 257 258 when(mRoleManager.getRoleHoldersAsUser( 259 ROLE_DIALER, 260 mUsers.get(0))) 261 .thenReturn(dialer0); 262 263 mRoleObserver.init(); 264 265 List<String> newDefault = new ArrayList<>(); 266 newDefault.add("phone"); 267 268 ArraySet<Pair<String, Integer>> newDefaultPair = new ArraySet<>(); 269 newDefaultPair.add(new Pair("phone", 30)); 270 when(mPm.getPackageUid("phone", MATCH_ALL, 0)).thenReturn(30); 271 272 when(mRoleManager.getRoleHoldersAsUser( 273 ROLE_DIALER, 274 mUsers.get(0))) 275 .thenReturn(newDefault); 276 277 mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0)); 278 279 verify(mPreferencesHelper, times(1)).updateDefaultApps( 280 0, new ArraySet<>(dialer0), newDefaultPair); 281 } 282 283 @Test testSwapDefault_forTrampolines()284 public void testSwapDefault_forTrampolines() throws Exception { 285 List<String> dialer0 = new ArrayList<>(); 286 when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30); 287 when(mPm.getPackageUid("com.browser2", MATCH_ALL, 0)).thenReturn(31); 288 when(mRoleManager.getRoleHoldersAsUser( 289 ROLE_BROWSER, 290 mUsers.get(0))) 291 .thenReturn(asList("com.browser")); 292 mRoleObserver.init(); 293 assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); 294 assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(31)); 295 // Default changed 296 when(mRoleManager.getRoleHoldersAsUser( 297 ROLE_BROWSER, 298 mUsers.get(0))) 299 .thenReturn(asList("com.browser2")); 300 mRoleObserver.onRoleHoldersChanged(ROLE_BROWSER, UserHandle.of(0)); 301 302 assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); 303 assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(31)); 304 } 305 306 @Test testSwapDefault_multipleOverlappingApps_forNonBlockableDefaultApps()307 public void testSwapDefault_multipleOverlappingApps_forNonBlockableDefaultApps() 308 throws Exception { 309 List<String> dialer0 = new ArrayList<>(); 310 dialer0.add("dialer"); 311 dialer0.add("phone"); 312 313 when(mRoleManager.getRoleHoldersAsUser( 314 ROLE_DIALER, 315 mUsers.get(0))) 316 .thenReturn(dialer0); 317 318 mRoleObserver.init(); 319 320 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0)); 321 assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0)); 322 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0)); 323 324 List<String> newDefault = new ArrayList<>(); 325 newDefault.add("phone"); 326 newDefault.add("emerPhone"); 327 328 when(mRoleManager.getRoleHoldersAsUser( 329 ROLE_DIALER, 330 mUsers.get(0))) 331 .thenReturn(newDefault); 332 333 ArraySet<String> expectedRemove = new ArraySet<>(); 334 expectedRemove.add("dialer"); 335 336 ArraySet<Pair<String, Integer>> expectedAddPair = new ArraySet<>(); 337 expectedAddPair.add(new Pair("emerPhone", 30)); 338 when(mPm.getPackageUid("emerPhone", MATCH_ALL, 0)).thenReturn(30); 339 340 mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0)); 341 342 verify(mPreferencesHelper, times(1)).updateDefaultApps( 343 0, expectedRemove, expectedAddPair); 344 345 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0)); 346 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0)); 347 assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0)); 348 } 349 350 @Test testSwapDefault_newUser_forNonBlockableDefaultApps()351 public void testSwapDefault_newUser_forNonBlockableDefaultApps() throws Exception { 352 List<String> dialer0 = new ArrayList<>(); 353 dialer0.add("dialer"); 354 355 when(mRoleManager.getRoleHoldersAsUser( 356 ROLE_DIALER, 357 mUsers.get(0))) 358 .thenReturn(dialer0); 359 360 mRoleObserver.init(); 361 362 List<String> dialer10 = new ArrayList<>(); 363 dialer10.add("phone"); 364 365 when(mRoleManager.getRoleHoldersAsUser( 366 ROLE_DIALER, 367 mUsers.get(1))) 368 .thenReturn(dialer10); 369 370 ArraySet<Pair<String, Integer>> expectedAddPair = new ArraySet<>(); 371 expectedAddPair.add(new Pair("phone", 30)); 372 when(mPm.getPackageUid("phone", MATCH_ALL, 10)).thenReturn(30); 373 374 mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(10)); 375 376 ArraySet<String> expectedRemove = new ArraySet<>(); 377 ArraySet<String> expectedAdd = new ArraySet<>(); 378 expectedAdd.add("phone"); 379 380 verify(mPreferencesHelper, times(1)).updateDefaultApps( 381 10, expectedRemove, expectedAddPair); 382 383 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 10)); 384 assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0)); 385 } 386 387 @Test testSwapDefault_newUser_forTrampolines()388 public void testSwapDefault_newUser_forTrampolines() throws Exception { 389 List<String> dialer0 = new ArrayList<>(); 390 when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30); 391 when(mPm.getPackageUid("com.browser2", MATCH_ALL, 10)).thenReturn(1031); 392 when(mRoleManager.getRoleHoldersAsUser( 393 ROLE_BROWSER, 394 mUsers.get(0))) 395 .thenReturn(asList("com.browser")); 396 mRoleObserver.init(); 397 assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); 398 assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(1031)); 399 // New user 400 when(mRoleManager.getRoleHoldersAsUser( 401 ROLE_BROWSER, 402 mUsers.get(1))) 403 .thenReturn(asList("com.browser2")); 404 mRoleObserver.onRoleHoldersChanged(ROLE_BROWSER, UserHandle.of(10)); 405 406 assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); 407 assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(1031)); 408 } 409 } 410