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.AccountManagerInternal;
     25 import android.accounts.AuthenticatorDescription;
     26 import android.app.AppOpsManager;
     27 import android.app.Notification;
     28 import android.content.BroadcastReceiver;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.content.IntentFilter;
     32 import android.content.pm.PackageManager;
     33 import android.content.pm.RegisteredServicesCache.ServiceInfo;
     34 import android.content.pm.RegisteredServicesCacheListener;
     35 import android.content.pm.UserInfo;
     36 import android.database.Cursor;
     37 import android.database.DatabaseErrorHandler;
     38 import android.database.sqlite.SQLiteDatabase;
     39 import android.os.Bundle;
     40 import android.os.Handler;
     41 import android.os.UserHandle;
     42 import android.os.UserManager;
     43 import android.test.AndroidTestCase;
     44 import android.test.mock.MockContext;
     45 import android.test.mock.MockPackageManager;
     46 import android.util.Log;
     47 
     48 import com.android.server.LocalServices;
     49 
     50 import java.io.File;
     51 import java.io.FileDescriptor;
     52 import java.io.PrintWriter;
     53 import java.util.ArrayList;
     54 import java.util.Arrays;
     55 import java.util.Collection;
     56 import java.util.Comparator;
     57 
     58 public 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