AccountManagerServiceTest.java revision d9543578609c6035aa97844b45143a2ce6ff1bfe
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 org.mockito.Matchers.eq; 20import static org.mockito.Mockito.mock; 21import static org.mockito.Mockito.when; 22 23import android.accounts.Account; 24import android.accounts.AccountManagerInternal; 25import android.accounts.AuthenticatorDescription; 26import android.app.AppOpsManager; 27import android.app.Notification; 28import android.content.BroadcastReceiver; 29import android.content.Context; 30import android.content.Intent; 31import android.content.IntentFilter; 32import android.content.pm.PackageManager; 33import android.content.pm.RegisteredServicesCache.ServiceInfo; 34import android.content.pm.RegisteredServicesCacheListener; 35import android.content.pm.UserInfo; 36import android.database.Cursor; 37import android.database.DatabaseErrorHandler; 38import android.database.sqlite.SQLiteDatabase; 39import android.os.Bundle; 40import android.os.Handler; 41import android.os.UserHandle; 42import android.os.UserManager; 43import android.test.AndroidTestCase; 44import android.test.mock.MockContext; 45import android.test.mock.MockPackageManager; 46import android.util.Log; 47 48import com.android.server.LocalServices; 49 50import java.io.File; 51import java.io.FileDescriptor; 52import java.io.PrintWriter; 53import java.util.ArrayList; 54import java.util.Arrays; 55import java.util.Collection; 56import java.util.Comparator; 57 58public class AccountManagerServiceTest extends AndroidTestCase { 59 private static final String TAG = AccountManagerServiceTest.class.getSimpleName(); 60 61 static final String PREN_DB = "pren.db"; 62 static final String DE_DB = "de.db"; 63 static final String CE_DB = "ce.db"; 64 private AccountManagerService mAms; 65 66 @Override 67 protected void setUp() throws Exception { 68 Context realTestContext = getContext(); 69 Context mockContext = new MyMockContext(realTestContext); 70 setContext(mockContext); 71 mAms = createAccountManagerService(mockContext, realTestContext); 72 } 73 74 @Override 75 protected void tearDown() throws Exception { 76 SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM))); 77 SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM))); 78 SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM))); 79 LocalServices.removeServiceForTest(AccountManagerInternal.class); 80 super.tearDown(); 81 } 82 83 public class AccountSorter implements Comparator<Account> { 84 public int compare(Account object1, Account object2) { 85 if (object1 == object2) return 0; 86 if (object1 == null) return 1; 87 if (object2 == null) return -1; 88 int result = object1.type.compareTo(object2.type); 89 if (result != 0) return result; 90 return object1.name.compareTo(object2.name); 91 } 92 } 93 94 public void testCheckAddAccount() throws Exception { 95 unlockSystemUser(); 96 Account a11 = new Account("account1", "type1"); 97 Account a21 = new Account("account2", "type1"); 98 Account a31 = new Account("account3", "type1"); 99 Account a12 = new Account("account1", "type2"); 100 Account a22 = new Account("account2", "type2"); 101 Account a32 = new Account("account3", "type2"); 102 mAms.addAccountExplicitly(a11, "p11", null); 103 mAms.addAccountExplicitly(a12, "p12", null); 104 mAms.addAccountExplicitly(a21, "p21", null); 105 mAms.addAccountExplicitly(a22, "p22", null); 106 mAms.addAccountExplicitly(a31, "p31", null); 107 mAms.addAccountExplicitly(a32, "p32", null); 108 109 Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); 110 Arrays.sort(accounts, new AccountSorter()); 111 assertEquals(6, accounts.length); 112 assertEquals(a11, accounts[0]); 113 assertEquals(a21, accounts[1]); 114 assertEquals(a31, accounts[2]); 115 assertEquals(a12, accounts[3]); 116 assertEquals(a22, accounts[4]); 117 assertEquals(a32, accounts[5]); 118 119 accounts = mAms.getAccounts("type1", mContext.getOpPackageName()); 120 Arrays.sort(accounts, new AccountSorter()); 121 assertEquals(3, accounts.length); 122 assertEquals(a11, accounts[0]); 123 assertEquals(a21, accounts[1]); 124 assertEquals(a31, accounts[2]); 125 126 mAms.removeAccountInternal(a21); 127 128 accounts = mAms.getAccounts("type1", mContext.getOpPackageName()); 129 Arrays.sort(accounts, new AccountSorter()); 130 assertEquals(2, accounts.length); 131 assertEquals(a11, accounts[0]); 132 assertEquals(a31, accounts[1]); 133 } 134 135 public void testPasswords() throws Exception { 136 unlockSystemUser(); 137 Account a11 = new Account("account1", "type1"); 138 Account a12 = new Account("account1", "type2"); 139 mAms.addAccountExplicitly(a11, "p11", null); 140 mAms.addAccountExplicitly(a12, "p12", null); 141 142 assertEquals("p11", mAms.getPassword(a11)); 143 assertEquals("p12", mAms.getPassword(a12)); 144 145 mAms.setPassword(a11, "p11b"); 146 147 assertEquals("p11b", mAms.getPassword(a11)); 148 assertEquals("p12", mAms.getPassword(a12)); 149 } 150 151 public void testUserdata() throws Exception { 152 unlockSystemUser(); 153 Account a11 = new Account("account1", "type1"); 154 Bundle u11 = new Bundle(); 155 u11.putString("a", "a_a11"); 156 u11.putString("b", "b_a11"); 157 u11.putString("c", "c_a11"); 158 Account a12 = new Account("account1", "type2"); 159 Bundle u12 = new Bundle(); 160 u12.putString("a", "a_a12"); 161 u12.putString("b", "b_a12"); 162 u12.putString("c", "c_a12"); 163 mAms.addAccountExplicitly(a11, "p11", u11); 164 mAms.addAccountExplicitly(a12, "p12", u12); 165 166 assertEquals("a_a11", mAms.getUserData(a11, "a")); 167 assertEquals("b_a11", mAms.getUserData(a11, "b")); 168 assertEquals("c_a11", mAms.getUserData(a11, "c")); 169 assertEquals("a_a12", mAms.getUserData(a12, "a")); 170 assertEquals("b_a12", mAms.getUserData(a12, "b")); 171 assertEquals("c_a12", mAms.getUserData(a12, "c")); 172 173 mAms.setUserData(a11, "b", "b_a11b"); 174 mAms.setUserData(a12, "c", null); 175 176 assertEquals("a_a11", mAms.getUserData(a11, "a")); 177 assertEquals("b_a11b", mAms.getUserData(a11, "b")); 178 assertEquals("c_a11", mAms.getUserData(a11, "c")); 179 assertEquals("a_a12", mAms.getUserData(a12, "a")); 180 assertEquals("b_a12", mAms.getUserData(a12, "b")); 181 assertNull(mAms.getUserData(a12, "c")); 182 } 183 184 public void testAuthtokens() throws Exception { 185 unlockSystemUser(); 186 Account a11 = new Account("account1", "type1"); 187 Account a12 = new Account("account1", "type2"); 188 mAms.addAccountExplicitly(a11, "p11", null); 189 mAms.addAccountExplicitly(a12, "p12", null); 190 191 mAms.setAuthToken(a11, "att1", "a11_att1"); 192 mAms.setAuthToken(a11, "att2", "a11_att2"); 193 mAms.setAuthToken(a11, "att3", "a11_att3"); 194 mAms.setAuthToken(a12, "att1", "a12_att1"); 195 mAms.setAuthToken(a12, "att2", "a12_att2"); 196 mAms.setAuthToken(a12, "att3", "a12_att3"); 197 198 assertEquals("a11_att1", mAms.peekAuthToken(a11, "att1")); 199 assertEquals("a11_att2", mAms.peekAuthToken(a11, "att2")); 200 assertEquals("a11_att3", mAms.peekAuthToken(a11, "att3")); 201 assertEquals("a12_att1", mAms.peekAuthToken(a12, "att1")); 202 assertEquals("a12_att2", mAms.peekAuthToken(a12, "att2")); 203 assertEquals("a12_att3", mAms.peekAuthToken(a12, "att3")); 204 205 mAms.setAuthToken(a11, "att3", "a11_att3b"); 206 mAms.invalidateAuthToken(a12.type, "a12_att2"); 207 208 assertEquals("a11_att1", mAms.peekAuthToken(a11, "att1")); 209 assertEquals("a11_att2", mAms.peekAuthToken(a11, "att2")); 210 assertEquals("a11_att3b", mAms.peekAuthToken(a11, "att3")); 211 assertEquals("a12_att1", mAms.peekAuthToken(a12, "att1")); 212 assertNull(mAms.peekAuthToken(a12, "att2")); 213 assertEquals("a12_att3", mAms.peekAuthToken(a12, "att3")); 214 215 assertNull(mAms.peekAuthToken(a12, "att2")); 216 } 217 218 public void testRemovedAccountSync() throws Exception { 219 unlockSystemUser(); 220 Account a1 = new Account("account1", "type1"); 221 Account a2 = new Account("account2", "type2"); 222 mAms.addAccountExplicitly(a1, "p1", null); 223 mAms.addAccountExplicitly(a2, "p2", null); 224 225 Context originalContext = ((MyMockContext)getContext()).mTestContext; 226 // create a separate instance of AMS. It initially assumes that user0 is locked 227 AccountManagerService ams2 = createAccountManagerService(getContext(), originalContext); 228 229 // Verify that account can be removed when user is locked 230 ams2.removeAccountInternal(a1); 231 Account[] accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName()); 232 assertEquals(1, accounts.length); 233 assertEquals("Only a2 should be returned", a2, accounts[0]); 234 235 // Verify that CE db file is unchanged and still has 2 accounts 236 String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM); 237 int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName); 238 assertEquals("CE database should still have 2 accounts", 2, accountsNumber); 239 240 // Unlock the user and verify that db has been updated 241 ams2.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM)); 242 accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName); 243 assertEquals("CE database should now have 1 account", 2, accountsNumber); 244 accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName()); 245 assertEquals(1, accounts.length); 246 assertEquals("Only a2 should be returned", a2, accounts[0]); 247 } 248 249 public void testPreNDatabaseMigration() throws Exception { 250 String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM); 251 Context originalContext = ((MyMockContext) getContext()).mTestContext; 252 PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName); 253 // Assert that database was created with 1 account 254 int n = readNumberOfAccountsFromDbFile(originalContext, preNDatabaseName); 255 assertEquals("pre-N database should have 1 account", 1, n); 256 257 // Start testing 258 unlockSystemUser(); 259 Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); 260 assertEquals("1 account should be migrated", 1, accounts.length); 261 assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name); 262 assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0])); 263 assertEquals("Authtoken should be migrated", 264 PreNTestDatabaseHelper.TOKEN_STRING, 265 mAms.peekAuthToken(accounts[0], PreNTestDatabaseHelper.TOKEN_TYPE)); 266 267 assertFalse("pre-N database file should be removed but was found at " + preNDatabaseName, 268 new File(preNDatabaseName).exists()); 269 270 // Verify that ce/de files are present 271 String deDatabaseName = mAms.getDeDatabaseName(UserHandle.USER_SYSTEM); 272 String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM); 273 assertTrue("DE database file should be created at " + deDatabaseName, 274 new File(deDatabaseName).exists()); 275 assertTrue("CE database file should be created at " + ceDatabaseName, 276 new File(ceDatabaseName).exists()); 277 } 278 279 private int readNumberOfAccountsFromDbFile(Context context, String dbName) { 280 SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null); 281 try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) { 282 assertTrue(cursor.moveToNext()); 283 return cursor.getInt(0); 284 } 285 } 286 287 private AccountManagerService createAccountManagerService(Context mockContext, 288 Context realContext) { 289 LocalServices.removeServiceForTest(AccountManagerInternal.class); 290 return new MyAccountManagerService(mockContext, 291 new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext); 292 } 293 294 private void unlockSystemUser() { 295 mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM)); 296 } 297 298 private static Intent newIntentForUser(int userId) { 299 Intent intent = new Intent(); 300 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 301 return intent; 302 } 303 304 static public class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache { 305 private ArrayList<ServiceInfo<AuthenticatorDescription>> mServices; 306 307 public MockAccountAuthenticatorCache() { 308 mServices = new ArrayList<>(); 309 AuthenticatorDescription d1 = new AuthenticatorDescription("type1", "p1", 0, 0, 0, 0); 310 AuthenticatorDescription d2 = new AuthenticatorDescription("type2", "p2", 0, 0, 0, 0); 311 mServices.add(new ServiceInfo<>(d1, null, null)); 312 mServices.add(new ServiceInfo<>(d2, null, null)); 313 } 314 315 @Override 316 public ServiceInfo<AuthenticatorDescription> getServiceInfo( 317 AuthenticatorDescription type, int userId) { 318 for (ServiceInfo<AuthenticatorDescription> service : mServices) { 319 if (service.type.equals(type)) { 320 return service; 321 } 322 } 323 return null; 324 } 325 326 @Override 327 public Collection<ServiceInfo<AuthenticatorDescription>> getAllServices(int userId) { 328 return mServices; 329 } 330 331 @Override 332 public void dump( 333 final FileDescriptor fd, final PrintWriter fout, final String[] args, int userId) { 334 } 335 336 @Override 337 public void setListener( 338 final RegisteredServicesCacheListener<AuthenticatorDescription> listener, 339 final Handler handler) { 340 } 341 342 @Override 343 public void invalidateCache(int userId) { 344 } 345 346 @Override 347 public void updateServices(int userId) { 348 } 349 } 350 351 static public class MyMockContext extends MockContext { 352 private Context mTestContext; 353 private AppOpsManager mAppOpsManager; 354 private UserManager mUserManager; 355 private PackageManager mPackageManager; 356 357 public MyMockContext(Context testContext) { 358 this.mTestContext = testContext; 359 this.mAppOpsManager = mock(AppOpsManager.class); 360 this.mUserManager = mock(UserManager.class); 361 this.mPackageManager = mock(PackageManager.class); 362 final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0); 363 when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui); 364 } 365 366 @Override 367 public int checkCallingOrSelfPermission(final String permission) { 368 return PackageManager.PERMISSION_GRANTED; 369 } 370 371 @Override 372 public PackageManager getPackageManager() { 373 return mPackageManager; 374 } 375 376 @Override 377 public Object getSystemService(String name) { 378 if (Context.APP_OPS_SERVICE.equals(name)) { 379 return mAppOpsManager; 380 } else if( Context.USER_SERVICE.equals(name)) { 381 return mUserManager; 382 } 383 return null; 384 } 385 386 @Override 387 public String getSystemServiceName(Class<?> serviceClass) { 388 if (AppOpsManager.class.equals(serviceClass)) { 389 return Context.APP_OPS_SERVICE; 390 } 391 return null; 392 } 393 394 @Override 395 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 396 return null; 397 } 398 399 @Override 400 public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, 401 IntentFilter filter, String broadcastPermission, Handler scheduler) { 402 return null; 403 } 404 405 @Override 406 public SQLiteDatabase openOrCreateDatabase(String file, int mode, 407 SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) { 408 Log.i(TAG, "openOrCreateDatabase " + file + " mode " + mode); 409 return mTestContext.openOrCreateDatabase(file, mode, factory,errorHandler); 410 } 411 412 @Override 413 public void sendBroadcastAsUser(Intent intent, UserHandle user) { 414 Log.i(TAG, "sendBroadcastAsUser " + intent + " " + user); 415 } 416 417 @Override 418 public String getOpPackageName() { 419 return null; 420 } 421 } 422 423 static public class MyMockPackageManager extends MockPackageManager { 424 @Override 425 public int checkSignatures(final int uid1, final int uid2) { 426 return PackageManager.SIGNATURE_MATCH; 427 } 428 429 @Override 430 public void addOnPermissionsChangeListener( 431 OnPermissionsChangedListener listener) { 432 } 433 } 434 435 static public class MyAccountManagerService extends AccountManagerService { 436 private Context mRealTestContext; 437 public MyAccountManagerService(Context context, PackageManager packageManager, 438 IAccountAuthenticatorCache authenticatorCache, Context realTestContext) { 439 super(context, packageManager, authenticatorCache); 440 this.mRealTestContext = realTestContext; 441 } 442 443 @Override 444 protected void installNotification(final int notificationId, final Notification n, UserHandle user) { 445 } 446 447 @Override 448 protected void cancelNotification(final int id, UserHandle user) { 449 } 450 451 @Override 452 protected String getCeDatabaseName(int userId) { 453 return new File(mRealTestContext.getCacheDir(), CE_DB).getPath(); 454 } 455 456 @Override 457 protected String getDeDatabaseName(int userId) { 458 return new File(mRealTestContext.getCacheDir(), DE_DB).getPath(); 459 } 460 461 @Override 462 String getPreNDatabaseName(int userId) { 463 return new File(mRealTestContext.getCacheDir(), PREN_DB).getPath(); 464 } 465 } 466} 467