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