Home | History | Annotate | Download | only in accounts
      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