AccountManagerServiceTest.java revision 81c4c8af206624f902efbd913fc3b26bb6842307
1/* 2 * Copyright (C) 2009 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 17package com.android.server.accounts; 18 19import static android.database.sqlite.SQLiteDatabase.deleteDatabase; 20import static org.mockito.Matchers.any; 21import static org.mockito.Matchers.anyBoolean; 22import static org.mockito.Matchers.anyInt; 23import static org.mockito.Matchers.anyString; 24import static org.mockito.Matchers.eq; 25import static org.mockito.Mockito.mock; 26import static org.mockito.Mockito.never; 27import static org.mockito.Mockito.verify; 28import static org.mockito.Mockito.when; 29 30import android.accounts.Account; 31import android.accounts.AccountManager; 32import android.accounts.AccountManagerInternal; 33import android.accounts.AuthenticatorDescription; 34import android.accounts.CantAddAccountActivity; 35import android.accounts.IAccountManagerResponse; 36import android.app.AppOpsManager; 37import android.app.admin.DevicePolicyManager; 38import android.app.admin.DevicePolicyManagerInternal; 39import android.app.INotificationManager; 40import android.content.BroadcastReceiver; 41import android.content.ComponentName; 42import android.content.Context; 43import android.content.Intent; 44import android.content.IntentFilter; 45import android.content.ServiceConnection; 46import android.content.pm.ActivityInfo; 47import android.content.pm.ApplicationInfo; 48import android.content.pm.PackageManager; 49import android.content.pm.RegisteredServicesCacheListener; 50import android.content.pm.ResolveInfo; 51import android.content.pm.UserInfo; 52import android.content.pm.RegisteredServicesCache.ServiceInfo; 53import android.database.Cursor; 54import android.database.DatabaseErrorHandler; 55import android.database.sqlite.SQLiteDatabase; 56import android.os.Bundle; 57import android.os.Handler; 58import android.os.IBinder; 59import android.os.Looper; 60import android.os.RemoteException; 61import android.os.UserHandle; 62import android.os.UserManager; 63import android.test.AndroidTestCase; 64import android.test.mock.MockContext; 65import android.test.suitebuilder.annotation.SmallTest; 66import android.util.Log; 67 68import com.android.frameworks.servicestests.R; 69import com.android.server.LocalServices; 70 71import org.mockito.ArgumentCaptor; 72import org.mockito.Captor; 73import org.mockito.Mock; 74import org.mockito.MockitoAnnotations; 75 76import java.io.File; 77import java.io.FileDescriptor; 78import java.io.PrintWriter; 79import java.util.ArrayList; 80import java.util.Arrays; 81import java.util.Collection; 82import java.util.Comparator; 83import java.util.concurrent.CountDownLatch; 84import java.util.concurrent.TimeUnit; 85 86public class AccountManagerServiceTest extends AndroidTestCase { 87 private static final String TAG = AccountManagerServiceTest.class.getSimpleName(); 88 89 @Mock private Context mMockContext; 90 @Mock private AppOpsManager mMockAppOpsManager; 91 @Mock private UserManager mMockUserManager; 92 @Mock private PackageManager mMockPackageManager; 93 @Mock private DevicePolicyManagerInternal mMockDevicePolicyManagerInternal; 94 @Mock private DevicePolicyManager mMockDevicePolicyManager; 95 @Mock private IAccountManagerResponse mMockAccountManagerResponse; 96 @Mock private IBinder mMockBinder; 97 98 @Captor private ArgumentCaptor<Intent> mIntentCaptor; 99 @Captor private ArgumentCaptor<Bundle> mBundleCaptor; 100 101 private static final int LATCH_TIMEOUT_MS = 500; 102 private static final String PREN_DB = "pren.db"; 103 private static final String DE_DB = "de.db"; 104 private static final String CE_DB = "ce.db"; 105 private AccountManagerService mAms; 106 private TestInjector mTestInjector; 107 108 @Override 109 protected void setUp() throws Exception { 110 MockitoAnnotations.initMocks(this); 111 112 when(mMockPackageManager.checkSignatures(anyInt(), anyInt())) 113 .thenReturn(PackageManager.SIGNATURE_MATCH); 114 final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0); 115 when(mMockUserManager.getUserInfo(eq(ui.id))).thenReturn(ui); 116 when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); 117 when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager); 118 when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager); 119 when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn( 120 Context.APP_OPS_SERVICE); 121 when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn( 122 PackageManager.PERMISSION_GRANTED); 123 Bundle bundle = new Bundle(); 124 when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle); 125 when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( 126 mMockDevicePolicyManager); 127 when(mMockAccountManagerResponse.asBinder()).thenReturn(mMockBinder); 128 129 Context realTestContext = getContext(); 130 MyMockContext mockContext = new MyMockContext(realTestContext, mMockContext); 131 setContext(mockContext); 132 mTestInjector = new TestInjector(realTestContext, mockContext); 133 mAms = new AccountManagerService(mTestInjector); 134 } 135 136 @Override 137 protected void tearDown() throws Exception { 138 // Let async logging tasks finish, otherwise they may crash due to db being removed 139 CountDownLatch cdl = new CountDownLatch(1); 140 mAms.mHandler.post(() -> { 141 deleteDatabase(new File(mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM))); 142 deleteDatabase(new File(mTestInjector.getDeDatabaseName(UserHandle.USER_SYSTEM))); 143 deleteDatabase(new File(mTestInjector.getPreNDatabaseName(UserHandle.USER_SYSTEM))); 144 cdl.countDown(); 145 }); 146 cdl.await(1, TimeUnit.SECONDS); 147 super.tearDown(); 148 } 149 150 class AccountSorter implements Comparator<Account> { 151 public int compare(Account object1, Account object2) { 152 if (object1 == object2) return 0; 153 if (object1 == null) return 1; 154 if (object2 == null) return -1; 155 int result = object1.type.compareTo(object2.type); 156 if (result != 0) return result; 157 return object1.name.compareTo(object2.name); 158 } 159 } 160 161 @SmallTest 162 public void testCheckAddAccount() throws Exception { 163 unlockSystemUser(); 164 Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 165 Account a21 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 166 Account a31 = new Account("account3", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 167 Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2); 168 Account a22 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2); 169 Account a32 = new Account("account3", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2); 170 mAms.addAccountExplicitly(a11, "p11", null); 171 mAms.addAccountExplicitly(a12, "p12", null); 172 mAms.addAccountExplicitly(a21, "p21", null); 173 mAms.addAccountExplicitly(a22, "p22", null); 174 mAms.addAccountExplicitly(a31, "p31", null); 175 mAms.addAccountExplicitly(a32, "p32", null); 176 177 Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); 178 Arrays.sort(accounts, new AccountSorter()); 179 assertEquals(6, accounts.length); 180 assertEquals(a11, accounts[0]); 181 assertEquals(a21, accounts[1]); 182 assertEquals(a31, accounts[2]); 183 assertEquals(a12, accounts[3]); 184 assertEquals(a22, accounts[4]); 185 assertEquals(a32, accounts[5]); 186 187 accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, 188 mContext.getOpPackageName()); 189 Arrays.sort(accounts, new AccountSorter()); 190 assertEquals(3, accounts.length); 191 assertEquals(a11, accounts[0]); 192 assertEquals(a21, accounts[1]); 193 assertEquals(a31, accounts[2]); 194 195 mAms.removeAccountInternal(a21); 196 197 accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, 198 mContext.getOpPackageName()); 199 Arrays.sort(accounts, new AccountSorter()); 200 assertEquals(2, accounts.length); 201 assertEquals(a11, accounts[0]); 202 assertEquals(a31, accounts[1]); 203 } 204 205 @SmallTest 206 public void testPasswords() throws Exception { 207 unlockSystemUser(); 208 Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 209 Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2); 210 mAms.addAccountExplicitly(a11, "p11", null); 211 mAms.addAccountExplicitly(a12, "p12", null); 212 213 assertEquals("p11", mAms.getPassword(a11)); 214 assertEquals("p12", mAms.getPassword(a12)); 215 216 mAms.setPassword(a11, "p11b"); 217 218 assertEquals("p11b", mAms.getPassword(a11)); 219 assertEquals("p12", mAms.getPassword(a12)); 220 } 221 222 @SmallTest 223 public void testUserdata() throws Exception { 224 unlockSystemUser(); 225 Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 226 Bundle u11 = new Bundle(); 227 u11.putString("a", "a_a11"); 228 u11.putString("b", "b_a11"); 229 u11.putString("c", "c_a11"); 230 Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2); 231 Bundle u12 = new Bundle(); 232 u12.putString("a", "a_a12"); 233 u12.putString("b", "b_a12"); 234 u12.putString("c", "c_a12"); 235 mAms.addAccountExplicitly(a11, "p11", u11); 236 mAms.addAccountExplicitly(a12, "p12", u12); 237 238 assertEquals("a_a11", mAms.getUserData(a11, "a")); 239 assertEquals("b_a11", mAms.getUserData(a11, "b")); 240 assertEquals("c_a11", mAms.getUserData(a11, "c")); 241 assertEquals("a_a12", mAms.getUserData(a12, "a")); 242 assertEquals("b_a12", mAms.getUserData(a12, "b")); 243 assertEquals("c_a12", mAms.getUserData(a12, "c")); 244 245 mAms.setUserData(a11, "b", "b_a11b"); 246 mAms.setUserData(a12, "c", null); 247 248 assertEquals("a_a11", mAms.getUserData(a11, "a")); 249 assertEquals("b_a11b", mAms.getUserData(a11, "b")); 250 assertEquals("c_a11", mAms.getUserData(a11, "c")); 251 assertEquals("a_a12", mAms.getUserData(a12, "a")); 252 assertEquals("b_a12", mAms.getUserData(a12, "b")); 253 assertNull(mAms.getUserData(a12, "c")); 254 } 255 256 @SmallTest 257 public void testAuthtokens() throws Exception { 258 unlockSystemUser(); 259 Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 260 Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2); 261 mAms.addAccountExplicitly(a11, "p11", null); 262 mAms.addAccountExplicitly(a12, "p12", null); 263 264 mAms.setAuthToken(a11, "att1", "a11_att1"); 265 mAms.setAuthToken(a11, "att2", "a11_att2"); 266 mAms.setAuthToken(a11, "att3", "a11_att3"); 267 mAms.setAuthToken(a12, "att1", "a12_att1"); 268 mAms.setAuthToken(a12, "att2", "a12_att2"); 269 mAms.setAuthToken(a12, "att3", "a12_att3"); 270 271 assertEquals("a11_att1", mAms.peekAuthToken(a11, "att1")); 272 assertEquals("a11_att2", mAms.peekAuthToken(a11, "att2")); 273 assertEquals("a11_att3", mAms.peekAuthToken(a11, "att3")); 274 assertEquals("a12_att1", mAms.peekAuthToken(a12, "att1")); 275 assertEquals("a12_att2", mAms.peekAuthToken(a12, "att2")); 276 assertEquals("a12_att3", mAms.peekAuthToken(a12, "att3")); 277 278 mAms.setAuthToken(a11, "att3", "a11_att3b"); 279 mAms.invalidateAuthToken(a12.type, "a12_att2"); 280 281 assertEquals("a11_att1", mAms.peekAuthToken(a11, "att1")); 282 assertEquals("a11_att2", mAms.peekAuthToken(a11, "att2")); 283 assertEquals("a11_att3b", mAms.peekAuthToken(a11, "att3")); 284 assertEquals("a12_att1", mAms.peekAuthToken(a12, "att1")); 285 assertNull(mAms.peekAuthToken(a12, "att2")); 286 assertEquals("a12_att3", mAms.peekAuthToken(a12, "att3")); 287 288 assertNull(mAms.peekAuthToken(a12, "att2")); 289 } 290 291 @SmallTest 292 public void testRemovedAccountSync() throws Exception { 293 unlockSystemUser(); 294 Account a1 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 295 Account a2 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2); 296 mAms.addAccountExplicitly(a1, "p1", null); 297 mAms.addAccountExplicitly(a2, "p2", null); 298 299 Context originalContext = ((MyMockContext)getContext()).mTestContext; 300 // create a separate instance of AMS. It initially assumes that user0 is locked 301 AccountManagerService ams2 = new AccountManagerService(mTestInjector); 302 303 // Verify that account can be removed when user is locked 304 ams2.removeAccountInternal(a1); 305 Account[] accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName()); 306 assertEquals(1, accounts.length); 307 assertEquals("Only a2 should be returned", a2, accounts[0]); 308 309 // Verify that CE db file is unchanged and still has 2 accounts 310 String ceDatabaseName = mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM); 311 int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName); 312 assertEquals("CE database should still have 2 accounts", 2, accountsNumber); 313 314 // Unlock the user and verify that db has been updated 315 ams2.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM)); 316 accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName()); 317 assertEquals(1, accounts.length); 318 assertEquals("Only a2 should be returned", a2, accounts[0]); 319 accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName); 320 assertEquals("CE database should now have 1 account", 1, accountsNumber); 321 } 322 323 @SmallTest 324 public void testPreNDatabaseMigration() throws Exception { 325 String preNDatabaseName = mTestInjector.getPreNDatabaseName(UserHandle.USER_SYSTEM); 326 Context originalContext = ((MyMockContext) getContext()).mTestContext; 327 PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName); 328 // Assert that database was created with 1 account 329 int n = readNumberOfAccountsFromDbFile(originalContext, preNDatabaseName); 330 assertEquals("pre-N database should have 1 account", 1, n); 331 332 // Start testing 333 unlockSystemUser(); 334 Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); 335 assertEquals("1 account should be migrated", 1, accounts.length); 336 assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name); 337 assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0])); 338 assertEquals("Authtoken should be migrated", 339 PreNTestDatabaseHelper.TOKEN_STRING, 340 mAms.peekAuthToken(accounts[0], PreNTestDatabaseHelper.TOKEN_TYPE)); 341 342 assertFalse("pre-N database file should be removed but was found at " + preNDatabaseName, 343 new File(preNDatabaseName).exists()); 344 345 // Verify that ce/de files are present 346 String deDatabaseName = mTestInjector.getDeDatabaseName(UserHandle.USER_SYSTEM); 347 String ceDatabaseName = mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM); 348 assertTrue("DE database file should be created at " + deDatabaseName, 349 new File(deDatabaseName).exists()); 350 assertTrue("CE database file should be created at " + ceDatabaseName, 351 new File(ceDatabaseName).exists()); 352 } 353 354 @SmallTest 355 public void testStartAddAccountSessionWithNullResponse() throws Exception { 356 unlockSystemUser(); 357 try { 358 mAms.startAddAccountSession( 359 null, // response 360 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, 361 "authTokenType", 362 null, // requiredFeatures 363 true, // expectActivityLaunch 364 null); // optionsIn 365 fail("IllegalArgumentException expected. But no exception was thrown."); 366 } catch (IllegalArgumentException e) { 367 } catch(Exception e){ 368 fail(String.format("Expect IllegalArgumentException, but got %s.", e)); 369 } 370 } 371 372 @SmallTest 373 public void testStartAddAccountSessionWithNullAccountType() throws Exception { 374 unlockSystemUser(); 375 try { 376 mAms.startAddAccountSession( 377 mMockAccountManagerResponse, // response 378 null, // accountType 379 "authTokenType", 380 null, // requiredFeatures 381 true, // expectActivityLaunch 382 null); // optionsIn 383 fail("IllegalArgumentException expected. But no exception was thrown."); 384 } catch (IllegalArgumentException e) { 385 } catch(Exception e){ 386 fail(String.format("Expect IllegalArgumentException, but got %s.", e)); 387 } 388 } 389 390 @SmallTest 391 public void testStartAddAccountSessionUserCannotModifyAccountNoDPM() throws Exception { 392 unlockSystemUser(); 393 Bundle bundle = new Bundle(); 394 bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true); 395 when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle); 396 LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); 397 398 mAms.startAddAccountSession( 399 mMockAccountManagerResponse, // response 400 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 401 "authTokenType", 402 null, // requiredFeatures 403 true, // expectActivityLaunch 404 null); // optionsIn 405 verify(mMockAccountManagerResponse).onError( 406 eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString()); 407 verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM)); 408 409 // verify the intent for default CantAddAccountActivity is sent. 410 Intent intent = mIntentCaptor.getValue(); 411 assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName()); 412 assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0), 413 AccountManager.ERROR_CODE_USER_RESTRICTED); 414 } 415 416 @SmallTest 417 public void testStartAddAccountSessionUserCannotModifyAccountWithDPM() throws Exception { 418 unlockSystemUser(); 419 Bundle bundle = new Bundle(); 420 bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true); 421 when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle); 422 LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); 423 LocalServices.addService( 424 DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal); 425 when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent( 426 anyInt(), anyString())).thenReturn(new Intent()); 427 when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent( 428 anyInt(), anyBoolean())).thenReturn(new Intent()); 429 430 mAms.startAddAccountSession( 431 mMockAccountManagerResponse, // response 432 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 433 "authTokenType", 434 null, // requiredFeatures 435 true, // expectActivityLaunch 436 null); // optionsIn 437 438 verify(mMockAccountManagerResponse).onError( 439 eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString()); 440 verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM)); 441 verify(mMockDevicePolicyManagerInternal).createUserRestrictionSupportIntent( 442 anyInt(), anyString()); 443 } 444 445 @SmallTest 446 public void testStartAddAccountSessionUserCannotModifyAccountForTypeNoDPM() throws Exception { 447 unlockSystemUser(); 448 when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt())) 449 .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"}); 450 LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); 451 452 mAms.startAddAccountSession( 453 mMockAccountManagerResponse, // response 454 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 455 "authTokenType", 456 null, // requiredFeatures 457 true, // expectActivityLaunch 458 null); // optionsIn 459 460 verify(mMockAccountManagerResponse).onError( 461 eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString()); 462 verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM)); 463 464 // verify the intent for default CantAddAccountActivity is sent. 465 Intent intent = mIntentCaptor.getValue(); 466 assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName()); 467 assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0), 468 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE); 469 } 470 471 @SmallTest 472 public void testStartAddAccountSessionUserCannotModifyAccountForTypeWithDPM() throws Exception { 473 unlockSystemUser(); 474 when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( 475 mMockDevicePolicyManager); 476 when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt())) 477 .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"}); 478 479 LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); 480 LocalServices.addService( 481 DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal); 482 when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent( 483 anyInt(), anyString())).thenReturn(new Intent()); 484 when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent( 485 anyInt(), anyBoolean())).thenReturn(new Intent()); 486 487 mAms.startAddAccountSession( 488 mMockAccountManagerResponse, // response 489 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 490 "authTokenType", 491 null, // requiredFeatures 492 true, // expectActivityLaunch 493 null); // optionsIn 494 495 verify(mMockAccountManagerResponse).onError( 496 eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString()); 497 verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM)); 498 verify(mMockDevicePolicyManagerInternal).createShowAdminSupportIntent( 499 anyInt(), anyBoolean()); 500 } 501 502 @SmallTest 503 public void testStartAddAccountSessionUserSuccessWithoutPasswordForwarding() throws Exception { 504 unlockSystemUser(); 505 when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn( 506 PackageManager.PERMISSION_DENIED); 507 508 final CountDownLatch latch = new CountDownLatch(1); 509 Response response = new Response(latch, mMockAccountManagerResponse); 510 Bundle options = createOptionsWithAccountName( 511 AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS); 512 mAms.startAddAccountSession( 513 response, // response 514 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 515 "authTokenType", 516 null, // requiredFeatures 517 false, // expectActivityLaunch 518 options); // optionsIn 519 waitForLatch(latch); 520 verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture()); 521 Bundle result = mBundleCaptor.getValue(); 522 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); 523 assertNotNull(sessionBundle); 524 // Assert that session bundle is encrypted and hence data not visible. 525 assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1)); 526 // Assert password is not returned 527 assertNull(result.getString(AccountManager.KEY_PASSWORD)); 528 assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null)); 529 assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN, 530 result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN)); 531 } 532 533 @SmallTest 534 public void testStartAddAccountSessionUserSuccessWithPasswordForwarding() throws Exception { 535 unlockSystemUser(); 536 when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn( 537 PackageManager.PERMISSION_GRANTED); 538 539 final CountDownLatch latch = new CountDownLatch(1); 540 Response response = new Response(latch, mMockAccountManagerResponse); 541 Bundle options = createOptionsWithAccountName( 542 AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS); 543 mAms.startAddAccountSession( 544 response, // response 545 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 546 "authTokenType", 547 null, // requiredFeatures 548 false, // expectActivityLaunch 549 options); // optionsIn 550 551 waitForLatch(latch); 552 verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture()); 553 Bundle result = mBundleCaptor.getValue(); 554 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); 555 assertNotNull(sessionBundle); 556 // Assert that session bundle is encrypted and hence data not visible. 557 assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1)); 558 // Assert password is returned 559 assertEquals(result.getString(AccountManager.KEY_PASSWORD), 560 AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD); 561 assertNull(result.getString(AccountManager.KEY_AUTHTOKEN)); 562 assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN, 563 result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN)); 564 } 565 566 @SmallTest 567 public void testStartAddAccountSessionUserReturnWithInvalidIntent() throws Exception { 568 unlockSystemUser(); 569 ResolveInfo resolveInfo = new ResolveInfo(); 570 resolveInfo.activityInfo = new ActivityInfo(); 571 resolveInfo.activityInfo.applicationInfo = new ApplicationInfo(); 572 when(mMockPackageManager.resolveActivityAsUser( 573 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo); 574 when(mMockPackageManager.checkSignatures( 575 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH); 576 577 final CountDownLatch latch = new CountDownLatch(1); 578 Response response = new Response(latch, mMockAccountManagerResponse); 579 Bundle options = createOptionsWithAccountName( 580 AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE); 581 582 mAms.startAddAccountSession( 583 response, // response 584 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 585 "authTokenType", 586 null, // requiredFeatures 587 true, // expectActivityLaunch 588 options); // optionsIn 589 waitForLatch(latch); 590 verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class)); 591 verify(mMockAccountManagerResponse).onError( 592 eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString()); 593 } 594 595 @SmallTest 596 public void testStartAddAccountSessionUserReturnWithValidIntent() throws Exception { 597 unlockSystemUser(); 598 ResolveInfo resolveInfo = new ResolveInfo(); 599 resolveInfo.activityInfo = new ActivityInfo(); 600 resolveInfo.activityInfo.applicationInfo = new ApplicationInfo(); 601 when(mMockPackageManager.resolveActivityAsUser( 602 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo); 603 when(mMockPackageManager.checkSignatures( 604 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH); 605 606 final CountDownLatch latch = new CountDownLatch(1); 607 Response response = new Response(latch, mMockAccountManagerResponse); 608 Bundle options = createOptionsWithAccountName( 609 AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE); 610 611 mAms.startAddAccountSession( 612 response, // response 613 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 614 "authTokenType", 615 null, // requiredFeatures 616 true, // expectActivityLaunch 617 options); // optionsIn 618 waitForLatch(latch); 619 620 verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture()); 621 Bundle result = mBundleCaptor.getValue(); 622 Intent intent = result.getParcelable(AccountManager.KEY_INTENT); 623 assertNotNull(intent); 624 assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT)); 625 assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK)); 626 } 627 628 @SmallTest 629 public void testStartAddAccountSessionUserError() throws Exception { 630 unlockSystemUser(); 631 Bundle options = createOptionsWithAccountName( 632 AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR); 633 options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE); 634 options.putString(AccountManager.KEY_ERROR_MESSAGE, 635 AccountManagerServiceTestFixtures.ERROR_MESSAGE); 636 637 final CountDownLatch latch = new CountDownLatch(1); 638 Response response = new Response(latch, mMockAccountManagerResponse); 639 mAms.startAddAccountSession( 640 response, // response 641 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType 642 "authTokenType", 643 null, // requiredFeatures 644 false, // expectActivityLaunch 645 options); // optionsIn 646 647 waitForLatch(latch); 648 verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 649 AccountManagerServiceTestFixtures.ERROR_MESSAGE); 650 verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class)); 651 } 652 653 private void waitForLatch(CountDownLatch latch) { 654 try { 655 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 656 } catch (InterruptedException e) { 657 fail("should not throw an InterruptedException"); 658 } 659 } 660 661 private Bundle createOptionsWithAccountName(final String accountName) { 662 Bundle sessionBundle = new Bundle(); 663 sessionBundle.putString( 664 AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1, 665 AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1); 666 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, 667 AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); 668 Bundle options = new Bundle(); 669 options.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName); 670 options.putBundle(AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE, 671 sessionBundle); 672 options.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD, 673 AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD); 674 return options; 675 } 676 677 private int readNumberOfAccountsFromDbFile(Context context, String dbName) { 678 SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null); 679 try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) { 680 assertTrue(cursor.moveToNext()); 681 return cursor.getInt(0); 682 } 683 } 684 685 private void unlockSystemUser() { 686 mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM)); 687 } 688 689 private static Intent newIntentForUser(int userId) { 690 Intent intent = new Intent(); 691 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 692 return intent; 693 } 694 695 static class MyMockContext extends MockContext { 696 private Context mTestContext; 697 private Context mMockContext; 698 699 MyMockContext(Context testContext, Context mockContext) { 700 this.mTestContext = testContext; 701 this.mMockContext = mockContext; 702 } 703 704 @Override 705 public int checkCallingOrSelfPermission(final String permission) { 706 return mMockContext.checkCallingOrSelfPermission(permission); 707 } 708 709 @Override 710 public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, 711 UserHandle user) { 712 return mTestContext.bindServiceAsUser(service, conn, flags, user); 713 } 714 715 @Override 716 public void unbindService(ServiceConnection conn) { 717 mTestContext.unbindService(conn); 718 } 719 720 @Override 721 public PackageManager getPackageManager() { 722 return mMockContext.getPackageManager(); 723 } 724 725 @Override 726 public String getPackageName() { 727 return mTestContext.getPackageName(); 728 } 729 730 @Override 731 public Object getSystemService(String name) { 732 return mMockContext.getSystemService(name); 733 } 734 735 @Override 736 public String getSystemServiceName(Class<?> serviceClass) { 737 return mMockContext.getSystemServiceName(serviceClass); 738 } 739 740 @Override 741 public void startActivityAsUser(Intent intent, UserHandle user) { 742 mMockContext.startActivityAsUser(intent, user); 743 } 744 745 @Override 746 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 747 return mMockContext.registerReceiver(receiver, filter); 748 } 749 750 @Override 751 public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, 752 IntentFilter filter, String broadcastPermission, Handler scheduler) { 753 return mMockContext.registerReceiverAsUser( 754 receiver, user, filter, broadcastPermission, scheduler); 755 } 756 757 @Override 758 public SQLiteDatabase openOrCreateDatabase(String file, int mode, 759 SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) { 760 return mTestContext.openOrCreateDatabase(file, mode, factory,errorHandler); 761 } 762 763 @Override 764 public void sendBroadcastAsUser(Intent intent, UserHandle user) { 765 mMockContext.sendBroadcastAsUser(intent, user); 766 } 767 768 @Override 769 public String getOpPackageName() { 770 return mMockContext.getOpPackageName(); 771 } 772 } 773 774 static class TestAccountAuthenticatorCache extends AccountAuthenticatorCache { 775 public TestAccountAuthenticatorCache(Context realContext) { 776 super(realContext); 777 } 778 779 @Override 780 protected File getUserSystemDirectory(int userId) { 781 return new File(mContext.getCacheDir(), "authenticator"); 782 } 783 } 784 785 static class TestInjector extends AccountManagerService.Injector { 786 private Context mRealContext; 787 TestInjector(Context realContext, Context mockContext) { 788 super(mockContext); 789 mRealContext = realContext; 790 } 791 792 @Override 793 Looper getMessageHandlerLooper() { 794 return Looper.getMainLooper(); 795 } 796 797 @Override 798 void addLocalService(AccountManagerInternal service) { 799 } 800 801 @Override 802 IAccountAuthenticatorCache getAccountAuthenticatorCache() { 803 return new TestAccountAuthenticatorCache(mRealContext); 804 } 805 806 @Override 807 protected String getCeDatabaseName(int userId) { 808 return new File(mRealContext.getCacheDir(), CE_DB).getPath(); 809 } 810 811 @Override 812 protected String getDeDatabaseName(int userId) { 813 return new File(mRealContext.getCacheDir(), DE_DB).getPath(); 814 } 815 816 @Override 817 String getPreNDatabaseName(int userId) { 818 return new File(mRealContext.getCacheDir(), PREN_DB).getPath(); 819 } 820 821 @Override 822 INotificationManager getNotificationManager() { 823 return mock(INotificationManager.class); 824 } 825 } 826 827 class Response extends IAccountManagerResponse.Stub { 828 private CountDownLatch mLatch; 829 private IAccountManagerResponse mMockResponse; 830 public Response(CountDownLatch latch, IAccountManagerResponse mockResponse) { 831 mLatch = latch; 832 mMockResponse = mockResponse; 833 } 834 835 @Override 836 public void onResult(Bundle bundle) { 837 try { 838 mMockResponse.onResult(bundle); 839 } catch (RemoteException e) { 840 } 841 mLatch.countDown(); 842 } 843 844 @Override 845 public void onError(int code, String message) { 846 try { 847 mMockResponse.onError(code, message); 848 } catch (RemoteException e) { 849 } 850 mLatch.countDown(); 851 } 852 } 853} 854