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