• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.Manifest;
20 import android.accounts.AbstractAccountAuthenticator;
21 import android.accounts.Account;
22 import android.accounts.AccountAndUser;
23 import android.accounts.AccountAuthenticatorResponse;
24 import android.accounts.AccountManager;
25 import android.accounts.AccountManagerInternal;
26 import android.accounts.AccountManagerResponse;
27 import android.accounts.AuthenticatorDescription;
28 import android.accounts.CantAddAccountActivity;
29 import android.accounts.ChooseAccountActivity;
30 import android.accounts.GrantCredentialsPermissionActivity;
31 import android.accounts.IAccountAuthenticator;
32 import android.accounts.IAccountAuthenticatorResponse;
33 import android.accounts.IAccountManager;
34 import android.accounts.IAccountManagerResponse;
35 import android.annotation.IntRange;
36 import android.annotation.NonNull;
37 import android.annotation.Nullable;
38 import android.app.ActivityManager;
39 import android.app.ActivityThread;
40 import android.app.AppOpsManager;
41 import android.app.INotificationManager;
42 import android.app.Notification;
43 import android.app.NotificationManager;
44 import android.app.PendingIntent;
45 import android.app.admin.DeviceAdminInfo;
46 import android.app.admin.DevicePolicyManager;
47 import android.app.admin.DevicePolicyManagerInternal;
48 import android.content.BroadcastReceiver;
49 import android.content.ClipData;
50 import android.content.ComponentName;
51 import android.content.Context;
52 import android.content.Intent;
53 import android.content.IntentFilter;
54 import android.content.IntentSender;
55 import android.content.ServiceConnection;
56 import android.content.pm.ActivityInfo;
57 import android.content.pm.ApplicationInfo;
58 import android.content.pm.IPackageManager;
59 import android.content.pm.PackageInfo;
60 import android.content.pm.PackageManager;
61 import android.content.pm.PackageManager.NameNotFoundException;
62 import android.content.pm.PackageManagerInternal;
63 import android.content.pm.PackageParser;
64 import android.content.pm.RegisteredServicesCache;
65 import android.content.pm.RegisteredServicesCacheListener;
66 import android.content.pm.ResolveInfo;
67 import android.content.pm.Signature;
68 import android.content.pm.UserInfo;
69 import android.database.Cursor;
70 import android.database.sqlite.SQLiteStatement;
71 import android.os.Binder;
72 import android.os.Bundle;
73 import android.os.Environment;
74 import android.os.Handler;
75 import android.os.IBinder;
76 import android.os.Looper;
77 import android.os.Message;
78 import android.os.Parcel;
79 import android.os.Parcelable;
80 import android.os.Process;
81 import android.os.RemoteCallback;
82 import android.os.RemoteException;
83 import android.os.ResultReceiver;
84 import android.os.ShellCallback;
85 import android.os.StrictMode;
86 import android.os.SystemClock;
87 import android.os.UserHandle;
88 import android.os.UserManager;
89 import android.text.TextUtils;
90 import android.util.Log;
91 import android.util.Pair;
92 import android.util.Slog;
93 import android.util.SparseArray;
94 import android.util.SparseBooleanArray;
95 
96 import com.android.internal.R;
97 import com.android.internal.annotations.GuardedBy;
98 import com.android.internal.annotations.VisibleForTesting;
99 import com.android.internal.content.PackageMonitor;
100 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
101 import com.android.internal.notification.SystemNotificationChannels;
102 import com.android.internal.util.ArrayUtils;
103 import com.android.internal.util.DumpUtils;
104 import com.android.internal.util.IndentingPrintWriter;
105 import com.android.internal.util.Preconditions;
106 import com.android.server.LocalServices;
107 import com.android.server.ServiceThread;
108 import com.android.server.SystemService;
109 
110 import com.google.android.collect.Lists;
111 import com.google.android.collect.Sets;
112 
113 import java.io.File;
114 import java.io.FileDescriptor;
115 import java.io.PrintWriter;
116 import java.security.GeneralSecurityException;
117 import java.security.MessageDigest;
118 import java.security.NoSuchAlgorithmException;
119 import java.text.SimpleDateFormat;
120 import java.util.ArrayList;
121 import java.util.Arrays;
122 import java.util.Collection;
123 import java.util.Collections;
124 import java.util.Date;
125 import java.util.HashMap;
126 import java.util.HashSet;
127 import java.util.LinkedHashMap;
128 import java.util.List;
129 import java.util.Map;
130 import java.util.Map.Entry;
131 import java.util.Objects;
132 import java.util.Set;
133 import java.util.UUID;
134 import java.util.concurrent.CopyOnWriteArrayList;
135 import java.util.concurrent.atomic.AtomicReference;
136 
137 /**
138  * A system service that provides  account, password, and authtoken management for all
139  * accounts on the device. Some of these calls are implemented with the help of the corresponding
140  * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
141  * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
142  *    AccountManager accountManager = AccountManager.get(context);
143  * @hide
144  */
145 public class AccountManagerService
146         extends IAccountManager.Stub
147         implements RegisteredServicesCacheListener<AuthenticatorDescription> {
148     private static final String TAG = "AccountManagerService";
149 
150     public static class Lifecycle extends SystemService {
151         private AccountManagerService mService;
152 
Lifecycle(Context context)153         public Lifecycle(Context context) {
154             super(context);
155         }
156 
157         @Override
onStart()158         public void onStart() {
159             mService = new AccountManagerService(new Injector(getContext()));
160             publishBinderService(Context.ACCOUNT_SERVICE, mService);
161         }
162 
163         @Override
onUnlockUser(int userHandle)164         public void onUnlockUser(int userHandle) {
165             mService.onUnlockUser(userHandle);
166         }
167 
168         @Override
onStopUser(int userHandle)169         public void onStopUser(int userHandle) {
170             Slog.i(TAG, "onStopUser " + userHandle);
171             mService.purgeUserData(userHandle);
172         }
173     }
174 
175     final Context mContext;
176 
177     private final PackageManager mPackageManager;
178     private final AppOpsManager mAppOpsManager;
179     private UserManager mUserManager;
180     private final Injector mInjector;
181 
182     final MessageHandler mHandler;
183 
184     // Messages that can be sent on mHandler
185     private static final int MESSAGE_TIMED_OUT = 3;
186     private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
187 
188     private final IAccountAuthenticatorCache mAuthenticatorCache;
189     private static final String PRE_N_DATABASE_NAME = "accounts.db";
190     private static final Intent ACCOUNTS_CHANGED_INTENT;
191 
192     private static final int SIGNATURE_CHECK_MISMATCH = 0;
193     private static final int SIGNATURE_CHECK_MATCH = 1;
194     private static final int SIGNATURE_CHECK_UID_MATCH = 2;
195 
196     static {
197         ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
198         ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
199                 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
200     }
201 
202     private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
203 
204     static class UserAccounts {
205         private final int userId;
206         final AccountsDb accountsDb;
207         private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
208                 credentialsPermissionNotificationIds = new HashMap<>();
209         private final HashMap<Account, NotificationId> signinRequiredNotificationIds
210                 = new HashMap<>();
211         final Object cacheLock = new Object();
212         final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
213         /** protected by the {@link #cacheLock} */
214         final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
215         /** protected by the {@link #cacheLock} */
216         private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
217         /** protected by the {@link #cacheLock} */
218         private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
219         /** protected by the {@link #cacheLock} */
220         private final TokenCache accountTokenCaches = new TokenCache();
221         /** protected by the {@link #cacheLock} */
222         private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
223 
224         /** protected by the {@link #mReceiversForType},
225          *  type -> (packageName -> number of active receivers)
226          *  type == null is used to get notifications about all account types
227          */
228         private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
229 
230         /**
231          * protected by the {@link #cacheLock}
232          *
233          * Caches the previous names associated with an account. Previous names
234          * should be cached because we expect that when an Account is renamed,
235          * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
236          * want to know if the accounts they care about have been renamed.
237          *
238          * The previous names are wrapped in an {@link AtomicReference} so that
239          * we can distinguish between those accounts with no previous names and
240          * those whose previous names haven't been cached (yet).
241          */
242         private final HashMap<Account, AtomicReference<String>> previousNameCache =
243                 new HashMap<Account, AtomicReference<String>>();
244 
UserAccounts(Context context, int userId, File preNDbFile, File deDbFile)245         UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
246             this.userId = userId;
247             synchronized (dbLock) {
248                 synchronized (cacheLock) {
249                     accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
250                 }
251             }
252         }
253     }
254 
255     private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
256     private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
257     // Not thread-safe. Only use in synchronized context
258     private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
259     private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
260             mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
261 
262     private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
263     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
264 
265     /**
266      * This should only be called by system code. One should only call this after the service
267      * has started.
268      * @return a reference to the AccountManagerService instance
269      * @hide
270      */
getSingleton()271     public static AccountManagerService getSingleton() {
272         return sThis.get();
273     }
274 
AccountManagerService(Injector injector)275     public AccountManagerService(Injector injector) {
276         mInjector = injector;
277         mContext = injector.getContext();
278         mPackageManager = mContext.getPackageManager();
279         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
280         mHandler = new MessageHandler(injector.getMessageHandlerLooper());
281         mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
282         mAuthenticatorCache.setListener(this, null /* Handler */);
283 
284         sThis.set(this);
285 
286         IntentFilter intentFilter = new IntentFilter();
287         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
288         intentFilter.addDataScheme("package");
289         mContext.registerReceiver(new BroadcastReceiver() {
290             @Override
291             public void onReceive(Context context1, Intent intent) {
292                 // Don't delete accounts when updating a authenticator's
293                 // package.
294                 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
295                     /* Purging data requires file io, don't block the main thread. This is probably
296                      * less than ideal because we are introducing a race condition where old grants
297                      * could be exercised until they are purged. But that race condition existed
298                      * anyway with the broadcast receiver.
299                      *
300                      * Ideally, we would completely clear the cache, purge data from the database,
301                      * and then rebuild the cache. All under the cache lock. But that change is too
302                      * large at this point.
303                      */
304                     final String removedPackageName = intent.getData().getSchemeSpecificPart();
305                     Runnable purgingRunnable = new Runnable() {
306                         @Override
307                         public void run() {
308                             purgeOldGrantsAll();
309                             // Notify authenticator about removed app?
310                             removeVisibilityValuesForPackage(removedPackageName);
311                         }
312                     };
313                     mHandler.post(purgingRunnable);
314                 }
315             }
316         }, intentFilter);
317 
318         injector.addLocalService(new AccountManagerInternalImpl());
319 
320         IntentFilter userFilter = new IntentFilter();
321         userFilter.addAction(Intent.ACTION_USER_REMOVED);
322         mContext.registerReceiverAsUser(new BroadcastReceiver() {
323             @Override
324             public void onReceive(Context context, Intent intent) {
325                 String action = intent.getAction();
326                 if (Intent.ACTION_USER_REMOVED.equals(action)) {
327                     int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
328                     if (userId < 1) return;
329                     Slog.i(TAG, "User " + userId + " removed");
330                     purgeUserData(userId);
331                 }
332             }
333         }, UserHandle.ALL, userFilter, null, null);
334 
335         // Need to cancel account request notifications if the update/install can access the account
336         new PackageMonitor() {
337             @Override
338             public void onPackageAdded(String packageName, int uid) {
339                 // Called on a handler, and running as the system
340                 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
341             }
342 
343             @Override
344             public void onPackageUpdateFinished(String packageName, int uid) {
345                 // Called on a handler, and running as the system
346                 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
347             }
348         }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
349 
350         // Cancel account request notification if an app op was preventing the account access
351         mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
352                 new AppOpsManager.OnOpChangedInternalListener() {
353             @Override
354             public void onOpChanged(int op, String packageName) {
355                 try {
356                     final int userId = ActivityManager.getCurrentUser();
357                     final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
358                     final int mode = mAppOpsManager.checkOpNoThrow(
359                             AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
360                     if (mode == AppOpsManager.MODE_ALLOWED) {
361                         final long identity = Binder.clearCallingIdentity();
362                         try {
363                             cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
364                         } finally {
365                             Binder.restoreCallingIdentity(identity);
366                         }
367                     }
368                 } catch (NameNotFoundException e) {
369                     /* ignore */
370                 }
371             }
372         });
373 
374         // Cancel account request notification if a permission was preventing the account access
375         mPackageManager.addOnPermissionsChangeListener(
376                 (int uid) -> {
377             Account[] accounts = null;
378             String[] packageNames = mPackageManager.getPackagesForUid(uid);
379             if (packageNames != null) {
380                 final int userId = UserHandle.getUserId(uid);
381                 final long identity = Binder.clearCallingIdentity();
382                 try {
383                     for (String packageName : packageNames) {
384                                 // if app asked for permission we need to cancel notification even
385                                 // for O+ applications.
386                                 if (mPackageManager.checkPermission(
387                                         Manifest.permission.GET_ACCOUNTS,
388                                         packageName) != PackageManager.PERMISSION_GRANTED) {
389                                     continue;
390                                 }
391 
392                         if (accounts == null) {
393                             accounts = getAccountsAsUser(null, userId, "android");
394                             if (ArrayUtils.isEmpty(accounts)) {
395                                 return;
396                             }
397                         }
398 
399                         for (Account account : accounts) {
400                             cancelAccountAccessRequestNotificationIfNeeded(
401                                     account, uid, packageName, true);
402                         }
403                     }
404                 } finally {
405                     Binder.restoreCallingIdentity(identity);
406                 }
407             }
408         });
409     }
410 
411 
getBindInstantServiceAllowed(int userId)412     boolean getBindInstantServiceAllowed(int userId) {
413         return  mAuthenticatorCache.getBindInstantServiceAllowed(userId);
414     }
415 
setBindInstantServiceAllowed(int userId, boolean allowed)416     void setBindInstantServiceAllowed(int userId, boolean allowed) {
417         mAuthenticatorCache.setBindInstantServiceAllowed(userId, allowed);
418     }
419 
cancelAccountAccessRequestNotificationIfNeeded(int uid, boolean checkAccess)420     private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
421             boolean checkAccess) {
422         Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
423         for (Account account : accounts) {
424             cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
425         }
426     }
427 
cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid, boolean checkAccess)428     private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
429             boolean checkAccess) {
430         Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
431         for (Account account : accounts) {
432             cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
433         }
434     }
435 
cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid, boolean checkAccess)436     private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
437             boolean checkAccess) {
438         String[] packageNames = mPackageManager.getPackagesForUid(uid);
439         if (packageNames != null) {
440             for (String packageName : packageNames) {
441                 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
442                         packageName, checkAccess);
443             }
444         }
445     }
446 
cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid, String packageName, boolean checkAccess)447     private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
448             int uid, String packageName, boolean checkAccess) {
449         if (!checkAccess || hasAccountAccess(account, packageName,
450                 UserHandle.getUserHandleForUid(uid))) {
451             cancelNotification(getCredentialPermissionNotificationId(account,
452                     AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid),
453                     UserHandle.getUserHandleForUid(uid));
454         }
455     }
456 
457     @Override
addAccountExplicitlyWithVisibility(Account account, String password, Bundle extras, Map packageToVisibility)458     public boolean addAccountExplicitlyWithVisibility(Account account, String password,
459             Bundle extras, Map packageToVisibility) {
460         Bundle.setDefusable(extras, true);
461         int callingUid = Binder.getCallingUid();
462         int userId = UserHandle.getCallingUserId();
463         if (Log.isLoggable(TAG, Log.VERBOSE)) {
464             Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
465                     + ", pid " + Binder.getCallingPid());
466         }
467         Objects.requireNonNull(account, "account cannot be null");
468         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
469             String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
470                     callingUid, account.type);
471             throw new SecurityException(msg);
472         }
473         /*
474          * Child users are not allowed to add accounts. Only the accounts that are shared by the
475          * parent profile can be added to child profile.
476          *
477          * TODO: Only allow accounts that were shared to be added by a limited user.
478          */
479         // fails if the account already exists
480         long identityToken = clearCallingIdentity();
481         try {
482             UserAccounts accounts = getUserAccounts(userId);
483             return addAccountInternal(accounts, account, password, extras, callingUid,
484                     (Map<String, Integer>) packageToVisibility);
485         } finally {
486             restoreCallingIdentity(identityToken);
487         }
488     }
489 
490     @Override
getAccountsAndVisibilityForPackage(String packageName, String accountType)491     public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
492             String accountType) {
493         int callingUid = Binder.getCallingUid();
494         int userId = UserHandle.getCallingUserId();
495         boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
496         List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
497 
498         if ((accountType != null && !managedTypes.contains(accountType))
499                 || (accountType == null && !isSystemUid)) {
500             throw new SecurityException(
501                     "getAccountsAndVisibilityForPackage() called from unauthorized uid "
502                             + callingUid + " with packageName=" + packageName);
503         }
504         if (accountType != null) {
505             managedTypes = new ArrayList<String>();
506             managedTypes.add(accountType);
507         }
508 
509         long identityToken = clearCallingIdentity();
510         try {
511             UserAccounts accounts = getUserAccounts(userId);
512             return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
513                     accounts);
514         } finally {
515             restoreCallingIdentity(identityToken);
516         }
517     }
518 
519     /*
520      * accountTypes may not be null
521      */
getAccountsAndVisibilityForPackage(String packageName, List<String> accountTypes, Integer callingUid, UserAccounts accounts)522     private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
523             List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
524         if (!packageExistsForUser(packageName, accounts.userId)) {
525             Log.d(TAG, "Package not found " + packageName);
526             return new LinkedHashMap<>();
527         }
528 
529         Map<Account, Integer> result = new LinkedHashMap<>();
530         for (String accountType : accountTypes) {
531             synchronized (accounts.dbLock) {
532                 synchronized (accounts.cacheLock) {
533                     final Account[] accountsOfType = accounts.accountCache.get(accountType);
534                     if (accountsOfType != null) {
535                         for (Account account : accountsOfType) {
536                             result.put(account,
537                                     resolveAccountVisibility(account, packageName, accounts));
538                         }
539                     }
540                 }
541             }
542         }
543         return filterSharedAccounts(accounts, result, callingUid, packageName);
544     }
545 
546     @Override
getPackagesAndVisibilityForAccount(Account account)547     public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
548         Objects.requireNonNull(account, "account cannot be null");
549         int callingUid = Binder.getCallingUid();
550         int userId = UserHandle.getCallingUserId();
551         if (!isAccountManagedByCaller(account.type, callingUid, userId)
552                 && !isSystemUid(callingUid)) {
553             String msg =
554                     String.format("uid %s cannot get secrets for account %s", callingUid, account);
555             throw new SecurityException(msg);
556         }
557 
558         long identityToken = clearCallingIdentity();
559         try {
560             UserAccounts accounts = getUserAccounts(userId);
561             synchronized (accounts.dbLock) {
562                 synchronized (accounts.cacheLock) {
563                     return getPackagesAndVisibilityForAccountLocked(account, accounts);
564                 }
565             }
566         } finally {
567             restoreCallingIdentity(identityToken);
568         }
569 
570     }
571 
572     /**
573      * Returns Map with all package names and visibility values for given account.
574      * The method and returned map must be guarded by accounts.cacheLock
575      *
576      * @param account Account to get visibility values.
577      * @param accounts UserAccount that currently hosts the account and application
578      *
579      * @return Map with cache for package names to visibility.
580      */
getPackagesAndVisibilityForAccountLocked(Account account, UserAccounts accounts)581     private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
582             UserAccounts accounts) {
583         Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
584         if (accountVisibility == null) {
585             Log.d(TAG, "Visibility was not initialized");
586             accountVisibility = new HashMap<>();
587             accounts.visibilityCache.put(account, accountVisibility);
588         }
589         return accountVisibility;
590     }
591 
592     @Override
getAccountVisibility(Account account, String packageName)593     public int getAccountVisibility(Account account, String packageName) {
594         Objects.requireNonNull(account, "account cannot be null");
595         Objects.requireNonNull(packageName, "packageName cannot be null");
596         int callingUid = Binder.getCallingUid();
597         int userId = UserHandle.getCallingUserId();
598         if (!isAccountManagedByCaller(account.type, callingUid, userId)
599             && !isSystemUid(callingUid)) {
600             String msg = String.format(
601                     "uid %s cannot get secrets for accounts of type: %s",
602                     callingUid,
603                     account.type);
604             throw new SecurityException(msg);
605         }
606         long identityToken = clearCallingIdentity();
607         try {
608             UserAccounts accounts = getUserAccounts(userId);
609             if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
610                 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
611                 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
612                     return visibility;
613                 } else {
614                    return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
615                 }
616             }
617             if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) {
618                 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
619                 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
620                     return visibility;
621                 } else {
622                    return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
623                 }
624             }
625             return resolveAccountVisibility(account, packageName, accounts);
626         } finally {
627             restoreCallingIdentity(identityToken);
628         }
629     }
630 
631     /**
632      * Method returns visibility for given account and package name.
633      *
634      * @param account The account to check visibility.
635      * @param packageName Package name to check visibility.
636      * @param accounts UserAccount that currently hosts the account and application
637      *
638      * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
639      *
640      */
getAccountVisibilityFromCache(Account account, String packageName, UserAccounts accounts)641     private int getAccountVisibilityFromCache(Account account, String packageName,
642             UserAccounts accounts) {
643         synchronized (accounts.cacheLock) {
644             Map<String, Integer> accountVisibility =
645                     getPackagesAndVisibilityForAccountLocked(account, accounts);
646             Integer visibility = accountVisibility.get(packageName);
647             return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
648         }
649     }
650 
651     /**
652      * Method which handles default values for Account visibility.
653      *
654      * @param account The account to check visibility.
655      * @param packageName Package name to check visibility
656      * @param accounts UserAccount that currently hosts the account and application
657      *
658      * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
659      *
660      */
resolveAccountVisibility(Account account, @NonNull String packageName, UserAccounts accounts)661     private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
662             UserAccounts accounts) {
663         Objects.requireNonNull(packageName, "packageName cannot be null");
664         int uid = -1;
665         try {
666             long identityToken = clearCallingIdentity();
667             try {
668                 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
669             } finally {
670                 restoreCallingIdentity(identityToken);
671             }
672         } catch (NameNotFoundException e) {
673             Log.d(TAG, "Package not found " + e.getMessage());
674             return AccountManager.VISIBILITY_NOT_VISIBLE;
675         }
676 
677         // System visibility can not be restricted.
678         if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
679             return AccountManager.VISIBILITY_VISIBLE;
680         }
681 
682         int signatureCheckResult =
683                 checkPackageSignature(account.type, uid, accounts.userId);
684 
685         // Authenticator can not restrict visibility to itself.
686         if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
687             return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
688         }
689 
690         // Return stored value if it was set.
691         int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
692 
693         if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
694             return visibility;
695         }
696 
697         boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
698                 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
699 
700         // Device/Profile owner gets visibility by default.
701         if (isProfileOwner(uid)) {
702             return AccountManager.VISIBILITY_VISIBLE;
703         }
704 
705         boolean preO = isPreOApplication(packageName);
706         if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
707                 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
708                 || (checkReadContactsPermission(packageName, accounts.userId)
709                     && accountTypeManagesContacts(account.type, accounts.userId))
710                 || isPrivileged) {
711             // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
712             // match.
713             visibility = getAccountVisibilityFromCache(account,
714                     AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
715             if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
716                 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
717             }
718         } else {
719             visibility = getAccountVisibilityFromCache(account,
720                     AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
721             if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
722                 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
723             }
724         }
725         return visibility;
726     }
727 
728     /**
729      * Checks targetSdk for a package;
730      *
731      * @param packageName Package name
732      *
733      * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
734      *         undefined
735      */
isPreOApplication(String packageName)736     private boolean isPreOApplication(String packageName) {
737         try {
738             long identityToken = clearCallingIdentity();
739             ApplicationInfo applicationInfo;
740             try {
741                 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
742             } finally {
743                 restoreCallingIdentity(identityToken);
744             }
745 
746             if (applicationInfo != null) {
747                 int version = applicationInfo.targetSdkVersion;
748                 return version < android.os.Build.VERSION_CODES.O;
749             }
750             return true;
751         } catch (NameNotFoundException e) {
752             Log.d(TAG, "Package not found " + e.getMessage());
753             return true;
754         }
755     }
756 
757     @Override
setAccountVisibility(Account account, String packageName, int newVisibility)758     public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
759         Objects.requireNonNull(account, "account cannot be null");
760         Objects.requireNonNull(packageName, "packageName cannot be null");
761         int callingUid = Binder.getCallingUid();
762         int userId = UserHandle.getCallingUserId();
763         if (!isAccountManagedByCaller(account.type, callingUid, userId)
764             && !isSystemUid(callingUid)) {
765             String msg = String.format(
766                     "uid %s cannot get secrets for accounts of type: %s",
767                     callingUid,
768                     account.type);
769             throw new SecurityException(msg);
770         }
771         long identityToken = clearCallingIdentity();
772         try {
773             UserAccounts accounts = getUserAccounts(userId);
774             return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
775                 accounts);
776         } finally {
777             restoreCallingIdentity(identityToken);
778         }
779     }
780 
isVisible(int visibility)781     private boolean isVisible(int visibility) {
782         return visibility == AccountManager.VISIBILITY_VISIBLE ||
783             visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
784     }
785 
786     /**
787      * Updates visibility for given account name and package.
788      *
789      * @param account Account to update visibility.
790      * @param packageName Package name for which visibility is updated.
791      * @param newVisibility New visibility calue
792      * @param notify if the flag is set applications will get notification about visibility change
793      * @param accounts UserAccount that currently hosts the account and application
794      *
795      * @return True if account visibility was changed.
796      */
setAccountVisibility(Account account, String packageName, int newVisibility, boolean notify, UserAccounts accounts)797     private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
798             boolean notify, UserAccounts accounts) {
799         synchronized (accounts.dbLock) {
800             synchronized (accounts.cacheLock) {
801                 Map<String, Integer> packagesToVisibility;
802                 List<String> accountRemovedReceivers;
803                 if (notify) {
804                     if (isSpecialPackageKey(packageName)) {
805                         packagesToVisibility =
806                                 getRequestingPackages(account, accounts);
807                         accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
808                     } else {
809                         if (!packageExistsForUser(packageName, accounts.userId)) {
810                             return false; // package is not installed.
811                         }
812                         packagesToVisibility = new HashMap<>();
813                         packagesToVisibility.put(packageName,
814                                 resolveAccountVisibility(account, packageName, accounts));
815                         accountRemovedReceivers = new ArrayList<>();
816                         if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
817                             accountRemovedReceivers.add(packageName);
818                         }
819                     }
820                 } else {
821                     // Notifications will not be send - only used during add account.
822                     if (!isSpecialPackageKey(packageName) &&
823                             !packageExistsForUser(packageName, accounts.userId)) {
824                         // package is not installed and not meta value.
825                         return false;
826                     }
827                     packagesToVisibility = Collections.emptyMap();
828                     accountRemovedReceivers = Collections.emptyList();
829                 }
830 
831                 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
832                     return false;
833                 }
834 
835                 if (notify) {
836                     for (Entry<String, Integer> packageToVisibility : packagesToVisibility
837                             .entrySet()) {
838                         int oldVisibility = packageToVisibility.getValue();
839                         int currentVisibility =
840                             resolveAccountVisibility(account, packageName, accounts);
841                         if (isVisible(oldVisibility) != isVisible(currentVisibility)) {
842                             notifyPackage(packageToVisibility.getKey(), accounts);
843                         }
844                     }
845                     for (String packageNameToNotify : accountRemovedReceivers) {
846                         sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
847                     }
848                     sendAccountsChangedBroadcast(accounts.userId);
849                 }
850                 return true;
851             }
852         }
853     }
854 
855     // Update account visibility in cache and database.
updateAccountVisibilityLocked(Account account, String packageName, int newVisibility, UserAccounts accounts)856     private boolean updateAccountVisibilityLocked(Account account, String packageName,
857             int newVisibility, UserAccounts accounts) {
858         final long accountId = accounts.accountsDb.findDeAccountId(account);
859         if (accountId < 0) {
860             return false;
861         }
862 
863         final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
864         try {
865             if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
866                     newVisibility)) {
867                 return false;
868             }
869         } finally {
870             StrictMode.setThreadPolicy(oldPolicy);
871         }
872         Map<String, Integer> accountVisibility =
873             getPackagesAndVisibilityForAccountLocked(account, accounts);
874         accountVisibility.put(packageName, newVisibility);
875         return true;
876     }
877 
878     @Override
registerAccountListener(String[] accountTypes, String opPackageName)879     public void registerAccountListener(String[] accountTypes, String opPackageName) {
880         int callingUid = Binder.getCallingUid();
881         mAppOpsManager.checkPackage(callingUid, opPackageName);
882 
883         int userId = UserHandle.getCallingUserId();
884         long identityToken = clearCallingIdentity();
885         try {
886             UserAccounts accounts = getUserAccounts(userId);
887             registerAccountListener(accountTypes, opPackageName, accounts);
888         } finally {
889             restoreCallingIdentity(identityToken);
890         }
891     }
892 
registerAccountListener(String[] accountTypes, String opPackageName, UserAccounts accounts)893     private void registerAccountListener(String[] accountTypes, String opPackageName,
894             UserAccounts accounts) {
895         synchronized (accounts.mReceiversForType) {
896             if (accountTypes == null) {
897                 // null for any type
898                 accountTypes = new String[] {null};
899             }
900             for (String type : accountTypes) {
901                 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
902                 if (receivers == null) {
903                     receivers = new HashMap<>();
904                     accounts.mReceiversForType.put(type, receivers);
905                 }
906                 Integer cnt = receivers.get(opPackageName);
907                 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
908             }
909         }
910     }
911 
912     @Override
unregisterAccountListener(String[] accountTypes, String opPackageName)913     public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
914         int callingUid = Binder.getCallingUid();
915         mAppOpsManager.checkPackage(callingUid, opPackageName);
916         int userId = UserHandle.getCallingUserId();
917         long identityToken = clearCallingIdentity();
918         try {
919             UserAccounts accounts = getUserAccounts(userId);
920             unregisterAccountListener(accountTypes, opPackageName, accounts);
921         } finally {
922             restoreCallingIdentity(identityToken);
923         }
924     }
925 
unregisterAccountListener(String[] accountTypes, String opPackageName, UserAccounts accounts)926     private void unregisterAccountListener(String[] accountTypes, String opPackageName,
927             UserAccounts accounts) {
928         synchronized (accounts.mReceiversForType) {
929             if (accountTypes == null) {
930                 // null for any type
931                 accountTypes = new String[] {null};
932             }
933             for (String type : accountTypes) {
934                 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
935                 if (receivers == null || receivers.get(opPackageName) == null) {
936                     throw new IllegalArgumentException("attempt to unregister wrong receiver");
937                 }
938                 Integer cnt = receivers.get(opPackageName);
939                 if (cnt == 1) {
940                     receivers.remove(opPackageName);
941                 } else {
942                     receivers.put(opPackageName, cnt - 1);
943                 }
944             }
945         }
946     }
947 
948     // Send notification to all packages which can potentially see the account
sendNotificationAccountUpdated(Account account, UserAccounts accounts)949     private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
950         Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
951 
952         for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
953             if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
954                     && (packageToVisibility.getValue()
955                         != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
956                 notifyPackage(packageToVisibility.getKey(), accounts);
957             }
958         }
959     }
960 
961     /**
962      * Sends a direct intent to a package, notifying it of account visibility change.
963      *
964      * @param packageName to send Account to
965      * @param accounts UserAccount that currently hosts the account
966      */
notifyPackage(String packageName, UserAccounts accounts)967     private void notifyPackage(String packageName, UserAccounts accounts) {
968         Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
969         intent.setPackage(packageName);
970         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
971         mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
972     }
973 
974     // Returns a map from package name to visibility, for packages subscribed
975     // to notifications about any account type, or type of provided account
976     // account type or all types.
getRequestingPackages(Account account, UserAccounts accounts)977     private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
978         Set<String> packages = new HashSet<>();
979         synchronized (accounts.mReceiversForType) {
980             for (String type : new String[] {account.type, null}) {
981                 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
982                 if (receivers != null) {
983                     packages.addAll(receivers.keySet());
984                 }
985             }
986         }
987         Map<String, Integer> result = new HashMap<>();
988         for (String packageName : packages) {
989             result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
990         }
991         return result;
992     }
993 
994     // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
getAccountRemovedReceivers(Account account, UserAccounts accounts)995     private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
996         Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
997         intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
998         List<ResolveInfo> receivers =
999             mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1000         List<String> result = new ArrayList<>();
1001         if (receivers == null) {
1002             return result;
1003         }
1004         for (ResolveInfo resolveInfo: receivers) {
1005             String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
1006             int visibility = resolveAccountVisibility(account, packageName, accounts);
1007             if (visibility == AccountManager.VISIBILITY_VISIBLE
1008                 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1009                 result.add(packageName);
1010             }
1011         }
1012         return result;
1013     }
1014 
1015     // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
shouldNotifyPackageOnAccountRemoval(Account account, String packageName, UserAccounts accounts)1016     private boolean shouldNotifyPackageOnAccountRemoval(Account account,
1017             String packageName, UserAccounts accounts) {
1018         int visibility = resolveAccountVisibility(account, packageName, accounts);
1019         if (visibility != AccountManager.VISIBILITY_VISIBLE
1020             && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1021             return false;
1022         }
1023 
1024         Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1025         intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1026         intent.setPackage(packageName);
1027         List<ResolveInfo> receivers =
1028             mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1029         return (receivers != null && receivers.size() > 0);
1030     }
1031 
packageExistsForUser(String packageName, int userId)1032     private boolean packageExistsForUser(String packageName, int userId) {
1033         try {
1034             long identityToken = clearCallingIdentity();
1035             try {
1036                 mPackageManager.getPackageUidAsUser(packageName, userId);
1037                 return true;
1038             } finally {
1039                 restoreCallingIdentity(identityToken);
1040             }
1041         } catch (NameNotFoundException e) {
1042             return false;
1043         }
1044     }
1045 
1046     /**
1047      * Returns true if packageName is one of special values.
1048      */
isSpecialPackageKey(String packageName)1049     private boolean isSpecialPackageKey(String packageName) {
1050         return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1051                 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1052     }
1053 
sendAccountsChangedBroadcast(int userId)1054     private void sendAccountsChangedBroadcast(int userId) {
1055         Log.i(TAG, "the accounts changed, sending broadcast of "
1056                 + ACCOUNTS_CHANGED_INTENT.getAction());
1057         mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
1058     }
1059 
sendAccountRemovedBroadcast(Account account, String packageName, int userId)1060     private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
1061         Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1062         intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1063         intent.setPackage(packageName);
1064         intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1065         intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
1066         mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1067     }
1068 
1069     @Override
onTransact(int code, Parcel data, Parcel reply, int flags)1070     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1071             throws RemoteException {
1072         try {
1073             return super.onTransact(code, data, reply, flags);
1074         } catch (RuntimeException e) {
1075             // The account manager only throws security exceptions, so let's
1076             // log all others.
1077             if (!(e instanceof SecurityException)) {
1078                 Slog.wtf(TAG, "Account Manager Crash", e);
1079             }
1080             throw e;
1081         }
1082     }
1083 
getUserManager()1084     private UserManager getUserManager() {
1085         if (mUserManager == null) {
1086             mUserManager = UserManager.get(mContext);
1087         }
1088         return mUserManager;
1089     }
1090 
1091     /**
1092      * Validate internal set of accounts against installed authenticators for
1093      * given user. Clears cached authenticators before validating.
1094      */
validateAccounts(int userId)1095     public void validateAccounts(int userId) {
1096         final UserAccounts accounts = getUserAccounts(userId);
1097         // Invalidate user-specific cache to make sure we catch any
1098         // removed authenticators.
1099         validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1100     }
1101 
1102     /**
1103      * Validate internal set of accounts against installed authenticators for
1104      * given user. Clear cached authenticators before validating when requested.
1105      */
validateAccountsInternal( UserAccounts accounts, boolean invalidateAuthenticatorCache)1106     private void validateAccountsInternal(
1107             UserAccounts accounts, boolean invalidateAuthenticatorCache) {
1108         if (Log.isLoggable(TAG, Log.DEBUG)) {
1109             Log.d(TAG, "validateAccountsInternal " + accounts.userId
1110                     + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
1111                     + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
1112         }
1113 
1114         if (invalidateAuthenticatorCache) {
1115             mAuthenticatorCache.invalidateCache(accounts.userId);
1116         }
1117 
1118         final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1119                 mAuthenticatorCache, accounts.userId);
1120         boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
1121 
1122         synchronized (accounts.dbLock) {
1123             synchronized (accounts.cacheLock) {
1124                 boolean accountDeleted = false;
1125 
1126                 // Get a map of stored authenticator types to UID
1127                 final AccountsDb accountsDb = accounts.accountsDb;
1128                 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1129                 // Create a list of authenticator type whose previous uid no longer exists
1130                 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1131                 SparseBooleanArray knownUids = null;
1132                 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1133                     String type = authToUidEntry.getKey();
1134                     int uid = authToUidEntry.getValue();
1135                     Integer knownUid = knownAuth.get(type);
1136                     if (knownUid != null && uid == knownUid) {
1137                         // Remove it from the knownAuth list if it's unchanged.
1138                         knownAuth.remove(type);
1139                     } else {
1140                     /*
1141                      * The authenticator is presently not cached and should only be triggered
1142                      * when we think an authenticator has been removed (or is being updated).
1143                      * But we still want to check if any data with the associated uid is
1144                      * around. This is an (imperfect) signal that the package may be updating.
1145                      *
1146                      * A side effect of this is that an authenticator sharing a uid with
1147                      * multiple apps won't get its credentials wiped as long as some app with
1148                      * that uid is still on the device. But I suspect that this is a rare case.
1149                      * And it isn't clear to me how an attacker could really exploit that
1150                      * feature.
1151                      *
1152                      * The upshot is that we don't have to worry about accounts getting
1153                      * uninstalled while the authenticator's package is being updated.
1154                      *
1155                      */
1156                         if (knownUids == null) {
1157                             knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1158                         }
1159                         if (!knownUids.get(uid)) {
1160                             // The authenticator is not presently available to the cache. And the
1161                             // package no longer has a data directory (so we surmise it isn't
1162                             // updating). So purge its data from the account databases.
1163                             obsoleteAuthType.add(type);
1164                             // And delete it from the TABLE_META
1165                             accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1166                         }
1167                     }
1168                 }
1169 
1170                 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1171                 // been re-enabled (after being updated for example), then we just overwrite the old
1172                 // values.
1173                 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1174                     accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1175                 }
1176 
1177                 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1178                 try {
1179                     accounts.accountCache.clear();
1180                     final HashMap<String, ArrayList<String>> accountNamesByType
1181                             = new LinkedHashMap<>();
1182                     for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1183                         final long accountId = accountEntry.getKey();
1184                         final Account account = accountEntry.getValue();
1185                         if (obsoleteAuthType.contains(account.type)) {
1186                             Slog.w(TAG, "deleting account " + account.toSafeString()
1187                                     + " because type " + account.type
1188                                     + "'s registered authenticator no longer exist.");
1189                             Map<String, Integer> packagesToVisibility =
1190                                     getRequestingPackages(account, accounts);
1191                             List<String> accountRemovedReceivers =
1192                                 getAccountRemovedReceivers(account, accounts);
1193                             accountsDb.beginTransaction();
1194                             try {
1195                                 accountsDb.deleteDeAccount(accountId);
1196                                 // Also delete from CE table if user is unlocked; if user is
1197                                 // currently locked the account will be removed later by
1198                                 // syncDeCeAccountsLocked
1199                                 if (userUnlocked) {
1200                                     accountsDb.deleteCeAccount(accountId);
1201                                 }
1202                                 accountsDb.setTransactionSuccessful();
1203                             } finally {
1204                                 accountsDb.endTransaction();
1205                             }
1206                             accountDeleted = true;
1207 
1208                             logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1209                                     AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
1210 
1211                             accounts.userDataCache.remove(account);
1212                             accounts.authTokenCache.remove(account);
1213                             accounts.accountTokenCaches.remove(account);
1214                             accounts.visibilityCache.remove(account);
1215 
1216                             for (Entry<String, Integer> packageToVisibility :
1217                                     packagesToVisibility.entrySet()) {
1218                                 if (isVisible(packageToVisibility.getValue())) {
1219                                     notifyPackage(packageToVisibility.getKey(), accounts);
1220                                 }
1221                             }
1222                             for (String packageName : accountRemovedReceivers) {
1223                                 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1224                             }
1225                         } else {
1226                             ArrayList<String> accountNames = accountNamesByType.get(account.type);
1227                             if (accountNames == null) {
1228                                 accountNames = new ArrayList<>();
1229                                 accountNamesByType.put(account.type, accountNames);
1230                             }
1231                             accountNames.add(account.name);
1232                         }
1233                     }
1234                     for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1235                         final String accountType = cur.getKey();
1236                         final ArrayList<String> accountNames = cur.getValue();
1237                         final Account[] accountsForType = new Account[accountNames.size()];
1238                         for (int i = 0; i < accountsForType.length; i++) {
1239                             accountsForType[i] = new Account(accountNames.get(i), accountType,
1240                                     UUID.randomUUID().toString());
1241                         }
1242                         accounts.accountCache.put(accountType, accountsForType);
1243                     }
1244                     accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1245                 } finally {
1246                     if (accountDeleted) {
1247                         sendAccountsChangedBroadcast(accounts.userId);
1248                     }
1249                 }
1250             }
1251         }
1252     }
1253 
getUidsOfInstalledOrUpdatedPackagesAsUser(int userId)1254     private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1255         // Get the UIDs of all apps that might have data on the device. We want
1256         // to preserve user data if the app might otherwise be storing data.
1257         List<PackageInfo> pkgsWithData =
1258                 mPackageManager.getInstalledPackagesAsUser(
1259                         PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1260         SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1261         for (PackageInfo pkgInfo : pkgsWithData) {
1262             if (pkgInfo.applicationInfo != null
1263                     && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1264                 knownUids.put(pkgInfo.applicationInfo.uid, true);
1265             }
1266         }
1267         return knownUids;
1268     }
1269 
getAuthenticatorTypeAndUIDForUser( Context context, int userId)1270     static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1271             Context context,
1272             int userId) {
1273         AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
1274         return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1275     }
1276 
getAuthenticatorTypeAndUIDForUser( IAccountAuthenticatorCache authCache, int userId)1277     private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1278             IAccountAuthenticatorCache authCache,
1279             int userId) {
1280         HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
1281         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1282                 .getAllServices(userId)) {
1283             knownAuth.put(service.type.type, service.uid);
1284         }
1285         return knownAuth;
1286     }
1287 
getUserAccountsForCaller()1288     private UserAccounts getUserAccountsForCaller() {
1289         return getUserAccounts(UserHandle.getCallingUserId());
1290     }
1291 
getUserAccounts(int userId)1292     protected UserAccounts getUserAccounts(int userId) {
1293         try {
1294             return getUserAccountsNotChecked(userId);
1295         } catch (RuntimeException e) {
1296             if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
1297                 // Let it go...
1298                 throw e;
1299             }
1300             // User accounts database is corrupted, we must wipe out the whole user, otherwise the
1301             // system will crash indefinitely
1302             Slog.wtf(TAG, "Removing user " + userId + " due to exception (" + e + ") reading its "
1303                     + "account database");
1304             if (userId == ActivityManager.getCurrentUser() && userId != UserHandle.USER_SYSTEM) {
1305                 Slog.i(TAG, "Switching to system user first");
1306                 try {
1307                     ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
1308                 } catch (RemoteException re) {
1309                     Slog.e(TAG, "Could not switch to " + UserHandle.USER_SYSTEM + ": " + re);
1310                 }
1311             }
1312             if (!getUserManager().removeUserEvenWhenDisallowed(userId)) {
1313                 Slog.e(TAG, "could not remove user " + userId);
1314             }
1315             throw e;
1316         }
1317     }
1318 
getUserAccountsNotChecked(int userId)1319     private UserAccounts getUserAccountsNotChecked(int userId) {
1320         synchronized (mUsers) {
1321             UserAccounts accounts = mUsers.get(userId);
1322             boolean validateAccounts = false;
1323             if (accounts == null) {
1324                 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1325                 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
1326                 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
1327                 mUsers.append(userId, accounts);
1328                 purgeOldGrants(accounts);
1329                 validateAccounts = true;
1330             }
1331             // open CE database if necessary
1332             if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
1333                 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
1334                 synchronized (accounts.dbLock) {
1335                     synchronized (accounts.cacheLock) {
1336                         File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1337                         accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1338                     }
1339                 }
1340                 syncDeCeAccountsLocked(accounts);
1341             }
1342             if (validateAccounts) {
1343                 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1344             }
1345             return accounts;
1346         }
1347     }
1348 
syncDeCeAccountsLocked(UserAccounts accounts)1349     private void syncDeCeAccountsLocked(UserAccounts accounts) {
1350         Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
1351         List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
1352         if (!accountsToRemove.isEmpty()) {
1353             Slog.i(TAG, accountsToRemove.size()
1354                     + " accounts were previously deleted while user "
1355                     + accounts.userId + " was locked. Removing accounts from CE tables");
1356             logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1357                     AccountsDb.TABLE_ACCOUNTS);
1358 
1359             for (Account account : accountsToRemove) {
1360                 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
1361             }
1362         }
1363     }
1364 
purgeOldGrantsAll()1365     private void purgeOldGrantsAll() {
1366         synchronized (mUsers) {
1367             for (int i = 0; i < mUsers.size(); i++) {
1368                 purgeOldGrants(mUsers.valueAt(i));
1369             }
1370         }
1371     }
1372 
purgeOldGrants(UserAccounts accounts)1373     private void purgeOldGrants(UserAccounts accounts) {
1374         synchronized (accounts.dbLock) {
1375             synchronized (accounts.cacheLock) {
1376                 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1377                 for (int uid : uids) {
1378                     final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1379                     if (packageExists) {
1380                         continue;
1381                     }
1382                     Log.d(TAG, "deleting grants for UID " + uid
1383                             + " because its package is no longer installed");
1384                     accounts.accountsDb.deleteGrantsByUid(uid);
1385                 }
1386             }
1387         }
1388     }
1389 
removeVisibilityValuesForPackage(String packageName)1390     private void removeVisibilityValuesForPackage(String packageName) {
1391         if (isSpecialPackageKey(packageName)) {
1392             return;
1393         }
1394         synchronized (mUsers) {
1395             int numberOfUsers = mUsers.size();
1396             for (int i = 0; i < numberOfUsers; i++) {
1397                 UserAccounts accounts = mUsers.valueAt(i);
1398                 try {
1399                     mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1400                 } catch (NameNotFoundException e) {
1401                     // package does not exist - remove visibility values
1402                     accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
1403                     synchronized (accounts.dbLock) {
1404                         synchronized (accounts.cacheLock) {
1405                             for (Account account : accounts.visibilityCache.keySet()) {
1406                                 Map<String, Integer> accountVisibility =
1407                                         getPackagesAndVisibilityForAccountLocked(account, accounts);
1408                                 accountVisibility.remove(packageName);
1409                             }
1410                         }
1411                     }
1412               }
1413           }
1414         }
1415     }
1416 
purgeUserData(int userId)1417     private void purgeUserData(int userId) {
1418         UserAccounts accounts;
1419         synchronized (mUsers) {
1420             accounts = mUsers.get(userId);
1421             mUsers.remove(userId);
1422             mLocalUnlockedUsers.delete(userId);
1423         }
1424         if (accounts != null) {
1425             synchronized (accounts.dbLock) {
1426                 synchronized (accounts.cacheLock) {
1427                     accounts.accountsDb.closeDebugStatement();
1428                     accounts.accountsDb.close();
1429                 }
1430             }
1431         }
1432     }
1433 
1434     @VisibleForTesting
onUserUnlocked(Intent intent)1435     void onUserUnlocked(Intent intent) {
1436         onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1437     }
1438 
onUnlockUser(int userId)1439     void onUnlockUser(int userId) {
1440         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1441             Log.v(TAG, "onUserUnlocked " + userId);
1442         }
1443         synchronized (mUsers) {
1444             mLocalUnlockedUsers.put(userId, true);
1445         }
1446         if (userId < 1) return;
1447         mHandler.post(() -> syncSharedAccounts(userId));
1448     }
1449 
syncSharedAccounts(int userId)1450     private void syncSharedAccounts(int userId) {
1451         // Check if there's a shared account that needs to be created as an account
1452         Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1453         if (sharedAccounts == null || sharedAccounts.length == 0) return;
1454         Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
1455         int parentUserId = UserManager.isSplitSystemUser()
1456                 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
1457                 : UserHandle.USER_SYSTEM;
1458         if (parentUserId < 0) {
1459             Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1460             return;
1461         }
1462         for (Account sa : sharedAccounts) {
1463             if (ArrayUtils.contains(accounts, sa)) continue;
1464             // Account doesn't exist. Copy it now.
1465             copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
1466         }
1467     }
1468 
1469     @Override
onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed)1470     public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
1471         UserInfo user = getUserManager().getUserInfo(userId);
1472         if (user == null) {
1473             Log.w(TAG, "onServiceChanged: ignore removed user " + userId);
1474             return;
1475         }
1476         validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
1477     }
1478 
1479     @Override
getPassword(Account account)1480     public String getPassword(Account account) {
1481         int callingUid = Binder.getCallingUid();
1482         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1483             Log.v(TAG, "getPassword: " + account
1484                     + ", caller's uid " + Binder.getCallingUid()
1485                     + ", pid " + Binder.getCallingPid());
1486         }
1487         if (account == null) throw new IllegalArgumentException("account is null");
1488         int userId = UserHandle.getCallingUserId();
1489         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
1490             String msg = String.format(
1491                     "uid %s cannot get secrets for accounts of type: %s",
1492                     callingUid,
1493                     account.type);
1494             throw new SecurityException(msg);
1495         }
1496         long identityToken = clearCallingIdentity();
1497         try {
1498             UserAccounts accounts = getUserAccounts(userId);
1499             return readPasswordInternal(accounts, account);
1500         } finally {
1501             restoreCallingIdentity(identityToken);
1502         }
1503     }
1504 
readPasswordInternal(UserAccounts accounts, Account account)1505     private String readPasswordInternal(UserAccounts accounts, Account account) {
1506         if (account == null) {
1507             return null;
1508         }
1509         if (!isLocalUnlockedUser(accounts.userId)) {
1510             Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1511             return null;
1512         }
1513 
1514         synchronized (accounts.dbLock) {
1515             synchronized (accounts.cacheLock) {
1516                 return accounts.accountsDb
1517                         .findAccountPasswordByNameAndType(account.name, account.type);
1518             }
1519         }
1520     }
1521 
1522     @Override
getPreviousName(Account account)1523     public String getPreviousName(Account account) {
1524         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1525             Log.v(TAG, "getPreviousName: " + account
1526                     + ", caller's uid " + Binder.getCallingUid()
1527                     + ", pid " + Binder.getCallingPid());
1528         }
1529         Objects.requireNonNull(account, "account cannot be null");
1530         int userId = UserHandle.getCallingUserId();
1531         long identityToken = clearCallingIdentity();
1532         try {
1533             UserAccounts accounts = getUserAccounts(userId);
1534             return readPreviousNameInternal(accounts, account);
1535         } finally {
1536             restoreCallingIdentity(identityToken);
1537         }
1538     }
1539 
readPreviousNameInternal(UserAccounts accounts, Account account)1540     private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1541         if  (account == null) {
1542             return null;
1543         }
1544         synchronized (accounts.dbLock) {
1545             synchronized (accounts.cacheLock) {
1546                 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1547                 if (previousNameRef == null) {
1548                     String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1549                     previousNameRef = new AtomicReference<>(previousName);
1550                     accounts.previousNameCache.put(account, previousNameRef);
1551                     return previousName;
1552                 } else {
1553                     return previousNameRef.get();
1554                 }
1555             }
1556         }
1557     }
1558 
1559     @Override
getUserData(Account account, String key)1560     public String getUserData(Account account, String key) {
1561         final int callingUid = Binder.getCallingUid();
1562         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1563             String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1564                     account, key, callingUid, Binder.getCallingPid());
1565             Log.v(TAG, msg);
1566         }
1567         Objects.requireNonNull(account, "account cannot be null");
1568         Objects.requireNonNull(key, "key cannot be null");
1569         int userId = UserHandle.getCallingUserId();
1570         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
1571             String msg = String.format(
1572                     "uid %s cannot get user data for accounts of type: %s",
1573                     callingUid,
1574                     account.type);
1575             throw new SecurityException(msg);
1576         }
1577         if (!isLocalUnlockedUser(userId)) {
1578             Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1579             return null;
1580         }
1581         long identityToken = clearCallingIdentity();
1582         try {
1583             UserAccounts accounts = getUserAccounts(userId);
1584             if (!accountExistsCache(accounts, account)) {
1585                 return null;
1586             }
1587             return readUserDataInternal(accounts, account, key);
1588         } finally {
1589             restoreCallingIdentity(identityToken);
1590         }
1591     }
1592 
1593     @Override
getAuthenticatorTypes(int userId)1594     public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
1595         int callingUid = Binder.getCallingUid();
1596         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1597             Log.v(TAG, "getAuthenticatorTypes: "
1598                     + "for user id " + userId
1599                     + " caller's uid " + callingUid
1600                     + ", pid " + Binder.getCallingPid());
1601         }
1602         // Only allow the system process to read accounts of other users
1603         if (isCrossUser(callingUid, userId)) {
1604             throw new SecurityException(
1605                     String.format(
1606                             "User %s tying to get authenticator types for %s" ,
1607                             UserHandle.getCallingUserId(),
1608                             userId));
1609         }
1610 
1611         final long identityToken = clearCallingIdentity();
1612         try {
1613             return getAuthenticatorTypesInternal(userId);
1614 
1615         } finally {
1616             restoreCallingIdentity(identityToken);
1617         }
1618     }
1619 
1620     /**
1621      * Should only be called inside of a clearCallingIdentity block.
1622      */
getAuthenticatorTypesInternal(int userId)1623     private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
1624         mAuthenticatorCache.updateServices(userId);
1625         Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1626                 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1627         AuthenticatorDescription[] types =
1628                 new AuthenticatorDescription[authenticatorCollection.size()];
1629         int i = 0;
1630         for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1631                 : authenticatorCollection) {
1632             types[i] = authenticator.type;
1633             i++;
1634         }
1635         return types;
1636     }
1637 
isCrossUser(int callingUid, int userId)1638     private boolean isCrossUser(int callingUid, int userId) {
1639         return (userId != UserHandle.getCallingUserId()
1640                 && callingUid != Process.SYSTEM_UID
1641                 && mContext.checkCallingOrSelfPermission(
1642                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1643                                 != PackageManager.PERMISSION_GRANTED);
1644     }
1645 
1646     @Override
addAccountExplicitly(Account account, String password, Bundle extras)1647     public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
1648         return addAccountExplicitlyWithVisibility(account, password, extras, null);
1649     }
1650 
1651     @Override
copyAccountToUser(final IAccountManagerResponse response, final Account account, final int userFrom, int userTo)1652     public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
1653             final int userFrom, int userTo) {
1654         int callingUid = Binder.getCallingUid();
1655         if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1656             throw new SecurityException("Calling copyAccountToUser requires "
1657                     + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1658         }
1659         final UserAccounts fromAccounts = getUserAccounts(userFrom);
1660         final UserAccounts toAccounts = getUserAccounts(userTo);
1661         if (fromAccounts == null || toAccounts == null) {
1662             if (response != null) {
1663                 Bundle result = new Bundle();
1664                 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1665                 try {
1666                     response.onResult(result);
1667                 } catch (RemoteException e) {
1668                     Slog.w(TAG, "Failed to report error back to the client." + e);
1669                 }
1670             }
1671             return;
1672         }
1673 
1674         Slog.d(TAG, "Copying account " + account.toSafeString()
1675                 + " from user " + userFrom + " to user " + userTo);
1676         long identityToken = clearCallingIdentity();
1677         try {
1678             new Session(fromAccounts, response, account.type, false,
1679                     false /* stripAuthTokenFromResult */, account.name,
1680                     false /* authDetailsRequired */) {
1681                 @Override
1682                 protected String toDebugString(long now) {
1683                     return super.toDebugString(now) + ", getAccountCredentialsForClone"
1684                             + ", " + account.type;
1685                 }
1686 
1687                 @Override
1688                 public void run() throws RemoteException {
1689                     mAuthenticator.getAccountCredentialsForCloning(this, account);
1690                 }
1691 
1692                 @Override
1693                 public void onResult(Bundle result) {
1694                     Bundle.setDefusable(result, true);
1695                     if (result != null
1696                             && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1697                         // Create a Session for the target user and pass in the bundle
1698                         completeCloningAccount(response, result, account, toAccounts, userFrom);
1699                     } else {
1700                         super.onResult(result);
1701                     }
1702                 }
1703             }.bind();
1704         } finally {
1705             restoreCallingIdentity(identityToken);
1706         }
1707     }
1708 
1709     @Override
accountAuthenticated(final Account account)1710     public boolean accountAuthenticated(final Account account) {
1711         final int callingUid = Binder.getCallingUid();
1712         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1713             String msg = String.format(
1714                     "accountAuthenticated( account: %s, callerUid: %s)",
1715                     account,
1716                     callingUid);
1717             Log.v(TAG, msg);
1718         }
1719         Objects.requireNonNull(account, "account cannot be null");
1720         int userId = UserHandle.getCallingUserId();
1721         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
1722             String msg = String.format(
1723                     "uid %s cannot notify authentication for accounts of type: %s",
1724                     callingUid,
1725                     account.type);
1726             throw new SecurityException(msg);
1727         }
1728 
1729         if (!canUserModifyAccounts(userId, callingUid) ||
1730                 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
1731             return false;
1732         }
1733 
1734         long identityToken = clearCallingIdentity();
1735         try {
1736             UserAccounts accounts = getUserAccounts(userId);
1737             return updateLastAuthenticatedTime(account);
1738         } finally {
1739             restoreCallingIdentity(identityToken);
1740         }
1741     }
1742 
updateLastAuthenticatedTime(Account account)1743     private boolean updateLastAuthenticatedTime(Account account) {
1744         final UserAccounts accounts = getUserAccountsForCaller();
1745         synchronized (accounts.dbLock) {
1746             synchronized (accounts.cacheLock) {
1747                 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1748             }
1749         }
1750     }
1751 
completeCloningAccount(IAccountManagerResponse response, final Bundle accountCredentials, final Account account, final UserAccounts targetUser, final int parentUserId)1752     private void completeCloningAccount(IAccountManagerResponse response,
1753             final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1754             final int parentUserId){
1755         Bundle.setDefusable(accountCredentials, true);
1756         long id = clearCallingIdentity();
1757         try {
1758             new Session(targetUser, response, account.type, false,
1759                     false /* stripAuthTokenFromResult */, account.name,
1760                     false /* authDetailsRequired */) {
1761                 @Override
1762                 protected String toDebugString(long now) {
1763                     return super.toDebugString(now) + ", getAccountCredentialsForClone"
1764                             + ", " + account.type;
1765                 }
1766 
1767                 @Override
1768                 public void run() throws RemoteException {
1769                     // Confirm that the owner's account still exists before this step.
1770                     for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1771                         if (acc.equals(account)) {
1772                             mAuthenticator.addAccountFromCredentials(
1773                                     this, account, accountCredentials);
1774                             break;
1775                         }
1776                     }
1777                 }
1778 
1779                 @Override
1780                 public void onResult(Bundle result) {
1781                     Bundle.setDefusable(result, true);
1782                     // TODO: Anything to do if if succedded?
1783                     // TODO: If it failed: Show error notification? Should we remove the shadow
1784                     // account to avoid retries?
1785                     // TODO: what we do with the visibility?
1786 
1787                     super.onResult(result);
1788                 }
1789 
1790                 @Override
1791                 public void onError(int errorCode, String errorMessage) {
1792                     super.onError(errorCode,  errorMessage);
1793                     // TODO: Show error notification to user
1794                     // TODO: Should we remove the shadow account so that it doesn't keep trying?
1795                 }
1796 
1797             }.bind();
1798         } finally {
1799             restoreCallingIdentity(id);
1800         }
1801     }
1802 
addAccountInternal(UserAccounts accounts, Account account, String password, Bundle extras, int callingUid, Map<String, Integer> packageToVisibility)1803     private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
1804             Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
1805         Bundle.setDefusable(extras, true);
1806         if (account == null) {
1807             return false;
1808         }
1809         if (!isLocalUnlockedUser(accounts.userId)) {
1810             Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
1811                     + accounts.userId + " is locked. callingUid=" + callingUid);
1812             return false;
1813         }
1814         synchronized (accounts.dbLock) {
1815             synchronized (accounts.cacheLock) {
1816                 accounts.accountsDb.beginTransaction();
1817                 try {
1818                     if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1819                         Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
1820                                 + ", skipping since the account already exists");
1821                         return false;
1822                     }
1823                     long accountId = accounts.accountsDb.insertCeAccount(account, password);
1824                     if (accountId < 0) {
1825                         Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
1826                                 + ", skipping the DB insert failed");
1827                         return false;
1828                     }
1829                     // Insert into DE table
1830                     if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1831                         Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
1832                                 + ", skipping the DB insert failed");
1833                         return false;
1834                     }
1835                     if (extras != null) {
1836                         for (String key : extras.keySet()) {
1837                             final String value = extras.getString(key);
1838                             if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1839                                 Log.w(TAG, "insertAccountIntoDatabase: "
1840                                         + account.toSafeString()
1841                                         + ", skipping since insertExtra failed for key " + key);
1842                                 return false;
1843                             }
1844                         }
1845                     }
1846 
1847                     if (packageToVisibility != null) {
1848                         for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1849                             setAccountVisibility(account, entry.getKey() /* package */,
1850                                     entry.getValue() /* visibility */, false /* notify */,
1851                                     accounts);
1852                         }
1853                     }
1854                     accounts.accountsDb.setTransactionSuccessful();
1855 
1856                     logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1857                             accountId,
1858                             accounts, callingUid);
1859 
1860                     insertAccountIntoCacheLocked(accounts, account);
1861                 } finally {
1862                     accounts.accountsDb.endTransaction();
1863                 }
1864             }
1865         }
1866         if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1867             addAccountToLinkedRestrictedUsers(account, accounts.userId);
1868         }
1869 
1870         sendNotificationAccountUpdated(account, accounts);
1871         // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1872         sendAccountsChangedBroadcast(accounts.userId);
1873 
1874         return true;
1875     }
1876 
isLocalUnlockedUser(int userId)1877     private boolean isLocalUnlockedUser(int userId) {
1878         synchronized (mUsers) {
1879             return mLocalUnlockedUsers.get(userId);
1880         }
1881     }
1882 
1883     /**
1884      * Adds the account to all linked restricted users as shared accounts. If the user is currently
1885      * running, then clone the account too.
1886      * @param account the account to share with limited users
1887      *
1888      */
addAccountToLinkedRestrictedUsers(Account account, int parentUserId)1889     private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
1890         List<UserInfo> users = getUserManager().getUsers();
1891         for (UserInfo user : users) {
1892             if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
1893                 addSharedAccountAsUser(account, user.id);
1894                 if (isLocalUnlockedUser(user.id)) {
1895                     mHandler.sendMessage(mHandler.obtainMessage(
1896                             MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
1897                 }
1898             }
1899         }
1900     }
1901 
1902     @Override
hasFeatures(IAccountManagerResponse response, Account account, String[] features, String opPackageName)1903     public void hasFeatures(IAccountManagerResponse response,
1904             Account account, String[] features, String opPackageName) {
1905         int callingUid = Binder.getCallingUid();
1906         mAppOpsManager.checkPackage(callingUid, opPackageName);
1907         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1908             Log.v(TAG, "hasFeatures: " + account
1909                     + ", response " + response
1910                     + ", features " + Arrays.toString(features)
1911                     + ", caller's uid " + callingUid
1912                     + ", pid " + Binder.getCallingPid());
1913         }
1914         Preconditions.checkArgument(account != null, "account cannot be null");
1915         Preconditions.checkArgument(response != null, "response cannot be null");
1916         Preconditions.checkArgument(features != null, "features cannot be null");
1917         int userId = UserHandle.getCallingUserId();
1918         checkReadAccountsPermitted(callingUid, account.type, userId,
1919                 opPackageName);
1920 
1921         long identityToken = clearCallingIdentity();
1922         try {
1923             UserAccounts accounts = getUserAccounts(userId);
1924             new TestFeaturesSession(accounts, response, account, features).bind();
1925         } finally {
1926             restoreCallingIdentity(identityToken);
1927         }
1928     }
1929 
1930     private class TestFeaturesSession extends Session {
1931         private final String[] mFeatures;
1932         private final Account mAccount;
1933 
TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response, Account account, String[] features)1934         public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
1935                 Account account, String[] features) {
1936             super(accounts, response, account.type, false /* expectActivityLaunch */,
1937                     true /* stripAuthTokenFromResult */, account.name,
1938                     false /* authDetailsRequired */);
1939             mFeatures = features;
1940             mAccount = account;
1941         }
1942 
1943         @Override
run()1944         public void run() throws RemoteException {
1945             try {
1946                 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1947             } catch (RemoteException e) {
1948                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1949             }
1950         }
1951 
1952         @Override
onResult(Bundle result)1953         public void onResult(Bundle result) {
1954             Bundle.setDefusable(result, true);
1955             IAccountManagerResponse response = getResponseAndClose();
1956             if (response != null) {
1957                 try {
1958                     if (result == null) {
1959                         response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
1960                         return;
1961                     }
1962                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
1963                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1964                                 + response);
1965                     }
1966                     final Bundle newResult = new Bundle();
1967                     newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1968                             result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1969                     response.onResult(newResult);
1970                 } catch (RemoteException e) {
1971                     // if the caller is dead then there is no one to care about remote exceptions
1972                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
1973                         Log.v(TAG, "failure while notifying response", e);
1974                     }
1975                 }
1976             }
1977         }
1978 
1979         @Override
toDebugString(long now)1980         protected String toDebugString(long now) {
1981             return super.toDebugString(now) + ", hasFeatures"
1982                     + ", " + mAccount
1983                     + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1984         }
1985     }
1986 
1987     @Override
renameAccount( IAccountManagerResponse response, Account accountToRename, String newName)1988     public void renameAccount(
1989             IAccountManagerResponse response, Account accountToRename, String newName) {
1990         final int callingUid = Binder.getCallingUid();
1991         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1992             Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
1993                 + ", caller's uid " + callingUid
1994                 + ", pid " + Binder.getCallingPid());
1995         }
1996         if (accountToRename == null) throw new IllegalArgumentException("account is null");
1997         int userId = UserHandle.getCallingUserId();
1998         if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
1999             String msg = String.format(
2000                     "uid %s cannot rename accounts of type: %s",
2001                     callingUid,
2002                     accountToRename.type);
2003             throw new SecurityException(msg);
2004         }
2005         long identityToken = clearCallingIdentity();
2006         try {
2007             UserAccounts accounts = getUserAccounts(userId);
2008             Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
2009             Bundle result = new Bundle();
2010             result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
2011             result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
2012             result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
2013                     resultingAccount.getAccessId());
2014             try {
2015                 response.onResult(result);
2016             } catch (RemoteException e) {
2017                 Log.w(TAG, e.getMessage());
2018             }
2019         } finally {
2020             restoreCallingIdentity(identityToken);
2021         }
2022     }
2023 
renameAccountInternal( UserAccounts accounts, Account accountToRename, String newName)2024     private Account renameAccountInternal(
2025             UserAccounts accounts, Account accountToRename, String newName) {
2026         Account resultAccount = null;
2027         /*
2028          * Cancel existing notifications. Let authenticators
2029          * re-post notifications as required. But we don't know if
2030          * the authenticators have bound their notifications to
2031          * now stale account name data.
2032          *
2033          * With a rename api, we might not need to do this anymore but it
2034          * shouldn't hurt.
2035          */
2036         cancelNotification(
2037                 getSigninRequiredNotificationId(accounts, accountToRename),
2038                 new UserHandle(accounts.userId));
2039         synchronized(accounts.credentialsPermissionNotificationIds) {
2040             for (Pair<Pair<Account, String>, Integer> pair:
2041                     accounts.credentialsPermissionNotificationIds.keySet()) {
2042                 if (accountToRename.equals(pair.first.first)) {
2043                     NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
2044                     cancelNotification(id, new UserHandle(accounts.userId));
2045                 }
2046             }
2047         }
2048         synchronized (accounts.dbLock) {
2049             synchronized (accounts.cacheLock) {
2050                 List<String> accountRemovedReceivers =
2051                     getAccountRemovedReceivers(accountToRename, accounts);
2052                 accounts.accountsDb.beginTransaction();
2053                 Account renamedAccount = new Account(newName, accountToRename.type);
2054                 try {
2055                     if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
2056                         Log.e(TAG, "renameAccount failed - account with new name already exists");
2057                         return null;
2058                     }
2059                     final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2060                     if (accountId >= 0) {
2061                         accounts.accountsDb.renameCeAccount(accountId, newName);
2062                         if (accounts.accountsDb.renameDeAccount(
2063                                 accountId, newName, accountToRename.name)) {
2064                             accounts.accountsDb.setTransactionSuccessful();
2065                         } else {
2066                             Log.e(TAG, "renameAccount failed");
2067                             return null;
2068                         }
2069                     } else {
2070                         Log.e(TAG, "renameAccount failed - old account does not exist");
2071                         return null;
2072                     }
2073                 } finally {
2074                     accounts.accountsDb.endTransaction();
2075                 }
2076             /*
2077              * Database transaction was successful. Clean up cached
2078              * data associated with the account in the user profile.
2079              */
2080                 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
2081             /*
2082              * Extract the data and token caches before removing the
2083              * old account to preserve the user data associated with
2084              * the account.
2085              */
2086                 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2087                 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2088                 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2089                 removeAccountFromCacheLocked(accounts, accountToRename);
2090             /*
2091              * Update the cached data associated with the renamed
2092              * account.
2093              */
2094                 accounts.userDataCache.put(renamedAccount, tmpData);
2095                 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2096                 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2097                 accounts.previousNameCache.put(
2098                         renamedAccount,
2099                         new AtomicReference<>(accountToRename.name));
2100                 resultAccount = renamedAccount;
2101 
2102                 int parentUserId = accounts.userId;
2103                 if (canHaveProfile(parentUserId)) {
2104                 /*
2105                  * Owner or system user account was renamed, rename the account for
2106                  * those users with which the account was shared.
2107                  */
2108                     List<UserInfo> users = getUserManager().getUsers(true);
2109                     for (UserInfo user : users) {
2110                         if (user.isRestricted()
2111                                 && (user.restrictedProfileParentId == parentUserId)) {
2112                             renameSharedAccountAsUser(accountToRename, newName, user.id);
2113                         }
2114                     }
2115                 }
2116 
2117                 sendNotificationAccountUpdated(resultAccount, accounts);
2118                 sendAccountsChangedBroadcast(accounts.userId);
2119                 for (String packageName : accountRemovedReceivers) {
2120                     sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2121                 }
2122             }
2123         }
2124         return resultAccount;
2125     }
2126 
canHaveProfile(final int parentUserId)2127     private boolean canHaveProfile(final int parentUserId) {
2128         final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
2129         return userInfo != null && userInfo.canHaveProfile();
2130     }
2131 
2132     @Override
removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId)2133     public void removeAccountAsUser(IAccountManagerResponse response, Account account,
2134             boolean expectActivityLaunch, int userId) {
2135         final int callingUid = Binder.getCallingUid();
2136         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2137             Log.v(TAG, "removeAccount: " + account
2138                     + ", response " + response
2139                     + ", caller's uid " + callingUid
2140                     + ", pid " + Binder.getCallingPid()
2141                     + ", for user id " + userId);
2142         }
2143         Preconditions.checkArgument(account != null, "account cannot be null");
2144         Preconditions.checkArgument(response != null, "response cannot be null");
2145 
2146         // Only allow the system process to modify accounts of other users
2147         if (isCrossUser(callingUid, userId)) {
2148             throw new SecurityException(
2149                     String.format(
2150                             "User %s tying remove account for %s" ,
2151                             UserHandle.getCallingUserId(),
2152                             userId));
2153         }
2154         /*
2155          * Only the system, authenticator or profile owner should be allowed to remove accounts for
2156          * that authenticator.  This will let users remove accounts (via Settings in the system) but
2157          * not arbitrary applications (like competing authenticators).
2158          */
2159         UserHandle user = UserHandle.of(userId);
2160         if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
2161                 && !isSystemUid(callingUid)
2162                 && !isProfileOwner(callingUid)) {
2163             String msg = String.format(
2164                     "uid %s cannot remove accounts of type: %s",
2165                     callingUid,
2166                     account.type);
2167             throw new SecurityException(msg);
2168         }
2169         if (!canUserModifyAccounts(userId, callingUid)) {
2170             try {
2171                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2172                         "User cannot modify accounts");
2173             } catch (RemoteException re) {
2174             }
2175             return;
2176         }
2177         if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
2178             try {
2179                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2180                         "User cannot modify accounts of this type (policy).");
2181             } catch (RemoteException re) {
2182             }
2183             return;
2184         }
2185         long identityToken = clearCallingIdentity();
2186         UserAccounts accounts = getUserAccounts(userId);
2187         cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
2188         synchronized(accounts.credentialsPermissionNotificationIds) {
2189             for (Pair<Pair<Account, String>, Integer> pair:
2190                 accounts.credentialsPermissionNotificationIds.keySet()) {
2191                 if (account.equals(pair.first.first)) {
2192                     NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
2193                     cancelNotification(id, user);
2194                 }
2195             }
2196         }
2197         final long accountId = accounts.accountsDb.findDeAccountId(account);
2198         logRecord(
2199                 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2200                 AccountsDb.TABLE_ACCOUNTS,
2201                 accountId,
2202                 accounts,
2203                 callingUid);
2204         try {
2205             new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2206         } finally {
2207             restoreCallingIdentity(identityToken);
2208         }
2209     }
2210 
2211     @Override
removeAccountExplicitly(Account account)2212     public boolean removeAccountExplicitly(Account account) {
2213         final int callingUid = Binder.getCallingUid();
2214         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2215             Log.v(TAG, "removeAccountExplicitly: " + account
2216                     + ", caller's uid " + callingUid
2217                     + ", pid " + Binder.getCallingPid());
2218         }
2219         int userId = Binder.getCallingUserHandle().getIdentifier();
2220         if (account == null) {
2221             /*
2222              * Null accounts should result in returning false, as per
2223              * AccountManage.addAccountExplicitly(...) java doc.
2224              */
2225             Log.e(TAG, "account is null");
2226             return false;
2227         } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2228             String msg = String.format(
2229                     "uid %s cannot explicitly remove accounts of type: %s",
2230                     callingUid,
2231                     account.type);
2232             throw new SecurityException(msg);
2233         }
2234         UserAccounts accounts = getUserAccountsForCaller();
2235         final long accountId = accounts.accountsDb.findDeAccountId(account);
2236         logRecord(
2237                 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2238                 AccountsDb.TABLE_ACCOUNTS,
2239                 accountId,
2240                 accounts,
2241                 callingUid);
2242         long identityToken = clearCallingIdentity();
2243         try {
2244             return removeAccountInternal(accounts, account, callingUid);
2245         } finally {
2246             restoreCallingIdentity(identityToken);
2247         }
2248     }
2249 
2250     private class RemoveAccountSession extends Session {
2251         final Account mAccount;
RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response, Account account, boolean expectActivityLaunch)2252         public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
2253                 Account account, boolean expectActivityLaunch) {
2254             super(accounts, response, account.type, expectActivityLaunch,
2255                     true /* stripAuthTokenFromResult */, account.name,
2256                     false /* authDetailsRequired */);
2257             mAccount = account;
2258         }
2259 
2260         @Override
toDebugString(long now)2261         protected String toDebugString(long now) {
2262             return super.toDebugString(now) + ", removeAccount"
2263                     + ", account " + mAccount;
2264         }
2265 
2266         @Override
run()2267         public void run() throws RemoteException {
2268             mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2269         }
2270 
2271         @Override
onResult(Bundle result)2272         public void onResult(Bundle result) {
2273             Bundle.setDefusable(result, true);
2274             if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2275                     && !result.containsKey(AccountManager.KEY_INTENT)) {
2276                 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
2277                 if (removalAllowed) {
2278                     removeAccountInternal(mAccounts, mAccount, getCallingUid());
2279                 }
2280                 IAccountManagerResponse response = getResponseAndClose();
2281                 if (response != null) {
2282                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
2283                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2284                                 + response);
2285                     }
2286                     try {
2287                         response.onResult(result);
2288                     } catch (RemoteException e) {
2289                         Slog.e(TAG, "Error calling onResult()", e);
2290                     }
2291                 }
2292             }
2293             super.onResult(result);
2294         }
2295     }
2296 
2297     @VisibleForTesting
removeAccountInternal(Account account)2298     protected void removeAccountInternal(Account account) {
2299         removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
2300     }
2301 
removeAccountInternal(UserAccounts accounts, Account account, int callingUid)2302     private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
2303         boolean isChanged = false;
2304         boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
2305         if (!userUnlocked) {
2306             Slog.i(TAG, "Removing account " + account.toSafeString()
2307                     + " while user " + accounts.userId
2308                     + " is still locked. CE data will be removed later");
2309         }
2310         synchronized (accounts.dbLock) {
2311             synchronized (accounts.cacheLock) {
2312                 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2313                         accounts);
2314                 List<String> accountRemovedReceivers =
2315                     getAccountRemovedReceivers(account, accounts);
2316                 accounts.accountsDb.beginTransaction();
2317                 // Set to a dummy value, this will only be used if the database
2318                 // transaction succeeds.
2319                 long accountId = -1;
2320                 try {
2321                     accountId = accounts.accountsDb.findDeAccountId(account);
2322                     if (accountId >= 0) {
2323                         isChanged = accounts.accountsDb.deleteDeAccount(accountId);
2324                     }
2325                     // always delete from CE table if CE storage is available
2326                     // DE account could be removed while CE was locked
2327                     if (userUnlocked) {
2328                         long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2329                         if (ceAccountId >= 0) {
2330                             accounts.accountsDb.deleteCeAccount(ceAccountId);
2331                         }
2332                     }
2333                     accounts.accountsDb.setTransactionSuccessful();
2334                 } finally {
2335                     accounts.accountsDb.endTransaction();
2336                 }
2337                 if (isChanged) {
2338                     removeAccountFromCacheLocked(accounts, account);
2339                     for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2340                             .entrySet()) {
2341                         if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2342                                 || (packageToVisibility.getValue()
2343                                     == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
2344                             notifyPackage(packageToVisibility.getKey(), accounts);
2345                         }
2346                     }
2347 
2348                     // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2349                     sendAccountsChangedBroadcast(accounts.userId);
2350                     for (String packageName : accountRemovedReceivers) {
2351                         sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2352                     }
2353                     String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2354                             : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2355                     logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2356                 }
2357             }
2358         }
2359         long id = Binder.clearCallingIdentity();
2360         try {
2361             int parentUserId = accounts.userId;
2362             if (canHaveProfile(parentUserId)) {
2363                 // Remove from any restricted profiles that are sharing this account.
2364                 List<UserInfo> users = getUserManager().getUsers(true);
2365                 for (UserInfo user : users) {
2366                     if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
2367                         removeSharedAccountAsUser(account, user.id, callingUid);
2368                     }
2369                 }
2370             }
2371         } finally {
2372             Binder.restoreCallingIdentity(id);
2373         }
2374 
2375         if (isChanged) {
2376             synchronized (accounts.credentialsPermissionNotificationIds) {
2377                 for (Pair<Pair<Account, String>, Integer> key
2378                         : accounts.credentialsPermissionNotificationIds.keySet()) {
2379                     if (account.equals(key.first.first)
2380                             && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
2381                         final int uid = (Integer) key.second;
2382                         mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
2383                                 account, uid, false));
2384                     }
2385                 }
2386             }
2387         }
2388 
2389         return isChanged;
2390     }
2391 
2392     @Override
invalidateAuthToken(String accountType, String authToken)2393     public void invalidateAuthToken(String accountType, String authToken) {
2394         int callerUid = Binder.getCallingUid();
2395         Objects.requireNonNull(accountType, "accountType cannot be null");
2396         Objects.requireNonNull(authToken, "authToken cannot be null");
2397         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2398             Log.v(TAG, "invalidateAuthToken: accountType " + accountType
2399                     + ", caller's uid " + callerUid
2400                     + ", pid " + Binder.getCallingPid());
2401         }
2402         int userId = UserHandle.getCallingUserId();
2403         long identityToken = clearCallingIdentity();
2404         try {
2405             UserAccounts accounts = getUserAccounts(userId);
2406             List<Pair<Account, String>> deletedTokens;
2407             synchronized (accounts.dbLock) {
2408                 accounts.accountsDb.beginTransaction();
2409                 try {
2410                     deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2411                     accounts.accountsDb.setTransactionSuccessful();
2412                 } finally {
2413                     accounts.accountsDb.endTransaction();
2414                 }
2415                 synchronized (accounts.cacheLock) {
2416                     for (Pair<Account, String> tokenInfo : deletedTokens) {
2417                         Account act = tokenInfo.first;
2418                         String tokenType = tokenInfo.second;
2419                         writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
2420                     }
2421                     // wipe out cached token in memory.
2422                     accounts.accountTokenCaches.remove(accountType, authToken);
2423                 }
2424             }
2425         } finally {
2426             restoreCallingIdentity(identityToken);
2427         }
2428     }
2429 
invalidateAuthTokenLocked(UserAccounts accounts, String accountType, String authToken)2430     private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
2431             String authToken) {
2432         // TODO Move to AccountsDB
2433         List<Pair<Account, String>> results = new ArrayList<>();
2434         Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
2435 
2436         try {
2437             while (cursor.moveToNext()) {
2438                 String authTokenId = cursor.getString(0);
2439                 String accountName = cursor.getString(1);
2440                 String authTokenType = cursor.getString(2);
2441                 accounts.accountsDb.deleteAuthToken(authTokenId);
2442                 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
2443             }
2444         } finally {
2445             cursor.close();
2446         }
2447         return results;
2448     }
2449 
saveCachedToken( UserAccounts accounts, Account account, String callerPkg, byte[] callerSigDigest, String tokenType, String token, long expiryMillis)2450     private void saveCachedToken(
2451             UserAccounts accounts,
2452             Account account,
2453             String callerPkg,
2454             byte[] callerSigDigest,
2455             String tokenType,
2456             String token,
2457             long expiryMillis) {
2458 
2459         if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2460             return;
2461         }
2462         cancelNotification(getSigninRequiredNotificationId(accounts, account),
2463                 UserHandle.of(accounts.userId));
2464         synchronized (accounts.cacheLock) {
2465             accounts.accountTokenCaches.put(
2466                     account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
2467         }
2468     }
2469 
saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type, String authToken)2470     private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2471             String authToken) {
2472         if (account == null || type == null) {
2473             return false;
2474         }
2475         cancelNotification(getSigninRequiredNotificationId(accounts, account),
2476                 UserHandle.of(accounts.userId));
2477         synchronized (accounts.dbLock) {
2478             accounts.accountsDb.beginTransaction();
2479             boolean updateCache = false;
2480             try {
2481                 long accountId = accounts.accountsDb.findDeAccountId(account);
2482                 if (accountId < 0) {
2483                     return false;
2484                 }
2485                 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2486                 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2487                     accounts.accountsDb.setTransactionSuccessful();
2488                     updateCache = true;
2489                     return true;
2490                 }
2491                 return false;
2492             } finally {
2493                 accounts.accountsDb.endTransaction();
2494                 if (updateCache) {
2495                     synchronized (accounts.cacheLock) {
2496                         writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2497                     }
2498                 }
2499             }
2500         }
2501     }
2502 
2503     @Override
peekAuthToken(Account account, String authTokenType)2504     public String peekAuthToken(Account account, String authTokenType) {
2505         final int callingUid = Binder.getCallingUid();
2506         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2507             Log.v(TAG, "peekAuthToken: " + account
2508                     + ", authTokenType " + authTokenType
2509                     + ", caller's uid " + callingUid
2510                     + ", pid " + Binder.getCallingPid());
2511         }
2512         Objects.requireNonNull(account, "account cannot be null");
2513         Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
2514         int userId = UserHandle.getCallingUserId();
2515         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2516             String msg = String.format(
2517                     "uid %s cannot peek the authtokens associated with accounts of type: %s",
2518                     callingUid,
2519                     account.type);
2520             throw new SecurityException(msg);
2521         }
2522         if (!isLocalUnlockedUser(userId)) {
2523             Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2524                     + callingUid);
2525             return null;
2526         }
2527         long identityToken = clearCallingIdentity();
2528         try {
2529             UserAccounts accounts = getUserAccounts(userId);
2530             return readAuthTokenInternal(accounts, account, authTokenType);
2531         } finally {
2532             restoreCallingIdentity(identityToken);
2533         }
2534     }
2535 
2536     @Override
setAuthToken(Account account, String authTokenType, String authToken)2537     public void setAuthToken(Account account, String authTokenType, String authToken) {
2538         final int callingUid = Binder.getCallingUid();
2539         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2540             Log.v(TAG, "setAuthToken: " + account
2541                     + ", authTokenType " + authTokenType
2542                     + ", caller's uid " + callingUid
2543                     + ", pid " + Binder.getCallingPid());
2544         }
2545         Objects.requireNonNull(account, "account cannot be null");
2546         Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
2547         int userId = UserHandle.getCallingUserId();
2548         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2549             String msg = String.format(
2550                     "uid %s cannot set auth tokens associated with accounts of type: %s",
2551                     callingUid,
2552                     account.type);
2553             throw new SecurityException(msg);
2554         }
2555         long identityToken = clearCallingIdentity();
2556         try {
2557             UserAccounts accounts = getUserAccounts(userId);
2558             saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
2559         } finally {
2560             restoreCallingIdentity(identityToken);
2561         }
2562     }
2563 
2564     @Override
setPassword(Account account, String password)2565     public void setPassword(Account account, String password) {
2566         final int callingUid = Binder.getCallingUid();
2567         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2568             Log.v(TAG, "setAuthToken: " + account
2569                     + ", caller's uid " + callingUid
2570                     + ", pid " + Binder.getCallingPid());
2571         }
2572         Objects.requireNonNull(account, "account cannot be null");
2573         int userId = UserHandle.getCallingUserId();
2574         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2575             String msg = String.format(
2576                     "uid %s cannot set secrets for accounts of type: %s",
2577                     callingUid,
2578                     account.type);
2579             throw new SecurityException(msg);
2580         }
2581         long identityToken = clearCallingIdentity();
2582         try {
2583             UserAccounts accounts = getUserAccounts(userId);
2584             setPasswordInternal(accounts, account, password, callingUid);
2585         } finally {
2586             restoreCallingIdentity(identityToken);
2587         }
2588     }
2589 
setPasswordInternal(UserAccounts accounts, Account account, String password, int callingUid)2590     private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2591             int callingUid) {
2592         if (account == null) {
2593             return;
2594         }
2595         boolean isChanged = false;
2596         synchronized (accounts.dbLock) {
2597             synchronized (accounts.cacheLock) {
2598                 accounts.accountsDb.beginTransaction();
2599                 try {
2600                     final long accountId = accounts.accountsDb.findDeAccountId(account);
2601                     if (accountId >= 0) {
2602                         accounts.accountsDb.updateCeAccountPassword(accountId, password);
2603                         accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2604                         accounts.authTokenCache.remove(account);
2605                         accounts.accountTokenCaches.remove(account);
2606                         accounts.accountsDb.setTransactionSuccessful();
2607                         // If there is an account whose password will be updated and the database
2608                         // transactions succeed, then we say that a change has occured. Even if the
2609                         // new password is the same as the old and there were no authtokens to
2610                         // delete.
2611                         isChanged = true;
2612                         String action = (password == null || password.length() == 0) ?
2613                                 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2614                                 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2615                         logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2616                                 callingUid);
2617                     }
2618                 } finally {
2619                     accounts.accountsDb.endTransaction();
2620                     if (isChanged) {
2621                         // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2622                         sendNotificationAccountUpdated(account, accounts);
2623                         sendAccountsChangedBroadcast(accounts.userId);
2624                     }
2625                 }
2626             }
2627         }
2628     }
2629 
2630     @Override
clearPassword(Account account)2631     public void clearPassword(Account account) {
2632         final int callingUid = Binder.getCallingUid();
2633         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2634             Log.v(TAG, "clearPassword: " + account
2635                     + ", caller's uid " + callingUid
2636                     + ", pid " + Binder.getCallingPid());
2637         }
2638         Objects.requireNonNull(account, "account cannot be null");
2639         int userId = UserHandle.getCallingUserId();
2640         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2641             String msg = String.format(
2642                     "uid %s cannot clear passwords for accounts of type: %s",
2643                     callingUid,
2644                     account.type);
2645             throw new SecurityException(msg);
2646         }
2647         long identityToken = clearCallingIdentity();
2648         try {
2649             UserAccounts accounts = getUserAccounts(userId);
2650             setPasswordInternal(accounts, account, null, callingUid);
2651         } finally {
2652             restoreCallingIdentity(identityToken);
2653         }
2654     }
2655 
2656     @Override
setUserData(Account account, String key, String value)2657     public void setUserData(Account account, String key, String value) {
2658         final int callingUid = Binder.getCallingUid();
2659         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2660             Log.v(TAG, "setUserData: " + account
2661                     + ", key " + key
2662                     + ", caller's uid " + callingUid
2663                     + ", pid " + Binder.getCallingPid());
2664         }
2665         if (key == null) throw new IllegalArgumentException("key is null");
2666         if (account == null) throw new IllegalArgumentException("account is null");
2667         int userId = UserHandle.getCallingUserId();
2668         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2669             String msg = String.format(
2670                     "uid %s cannot set user data for accounts of type: %s",
2671                     callingUid,
2672                     account.type);
2673             throw new SecurityException(msg);
2674         }
2675         long identityToken = clearCallingIdentity();
2676         try {
2677             UserAccounts accounts = getUserAccounts(userId);
2678             if (!accountExistsCache(accounts, account)) {
2679                 return;
2680             }
2681             setUserdataInternal(accounts, account, key, value);
2682         } finally {
2683             restoreCallingIdentity(identityToken);
2684         }
2685     }
2686 
accountExistsCache(UserAccounts accounts, Account account)2687     private boolean accountExistsCache(UserAccounts accounts, Account account) {
2688         synchronized (accounts.cacheLock) {
2689             if (accounts.accountCache.containsKey(account.type)) {
2690                 for (Account acc : accounts.accountCache.get(account.type)) {
2691                     if (acc.name.equals(account.name)) {
2692                         return true;
2693                     }
2694                 }
2695             }
2696         }
2697         return false;
2698     }
2699 
setUserdataInternal(UserAccounts accounts, Account account, String key, String value)2700     private void setUserdataInternal(UserAccounts accounts, Account account, String key,
2701             String value) {
2702         synchronized (accounts.dbLock) {
2703             accounts.accountsDb.beginTransaction();
2704             try {
2705                 long accountId = accounts.accountsDb.findDeAccountId(account);
2706                 if (accountId < 0) {
2707                     return;
2708                 }
2709                 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2710                 if (extrasId < 0) {
2711                     extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2712                     if (extrasId < 0) {
2713                         return;
2714                     }
2715                 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2716                     return;
2717                 }
2718                 accounts.accountsDb.setTransactionSuccessful();
2719             } finally {
2720                 accounts.accountsDb.endTransaction();
2721             }
2722             synchronized (accounts.cacheLock) {
2723                 writeUserDataIntoCacheLocked(accounts, account, key, value);
2724             }
2725         }
2726     }
2727 
onResult(IAccountManagerResponse response, Bundle result)2728     private void onResult(IAccountManagerResponse response, Bundle result) {
2729         if (result == null) {
2730             Log.e(TAG, "the result is unexpectedly null", new Exception());
2731         }
2732         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2733             Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2734                     + response);
2735         }
2736         try {
2737             response.onResult(result);
2738         } catch (RemoteException e) {
2739             // if the caller is dead then there is no one to care about remote
2740             // exceptions
2741             if (Log.isLoggable(TAG, Log.VERBOSE)) {
2742                 Log.v(TAG, "failure while notifying response", e);
2743             }
2744         }
2745     }
2746 
2747     @Override
getAuthTokenLabel(IAccountManagerResponse response, final String accountType, final String authTokenType)2748     public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2749                                   final String authTokenType)
2750             throws RemoteException {
2751         Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2752         Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
2753 
2754         final int callingUid = getCallingUid();
2755         clearCallingIdentity();
2756         if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
2757             throw new SecurityException("can only call from system");
2758         }
2759         int userId = UserHandle.getUserId(callingUid);
2760         long identityToken = clearCallingIdentity();
2761         try {
2762             UserAccounts accounts = getUserAccounts(userId);
2763             new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2764                     false /* stripAuthTokenFromResult */,  null /* accountName */,
2765                     false /* authDetailsRequired */) {
2766                 @Override
2767                 protected String toDebugString(long now) {
2768                     return super.toDebugString(now) + ", getAuthTokenLabel"
2769                             + ", " + accountType
2770                             + ", authTokenType " + authTokenType;
2771                 }
2772 
2773                 @Override
2774                 public void run() throws RemoteException {
2775                     mAuthenticator.getAuthTokenLabel(this, authTokenType);
2776                 }
2777 
2778                 @Override
2779                 public void onResult(Bundle result) {
2780                     Bundle.setDefusable(result, true);
2781                     if (result != null) {
2782                         String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2783                         Bundle bundle = new Bundle();
2784                         bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2785                         super.onResult(bundle);
2786                         return;
2787                     } else {
2788                         super.onResult(result);
2789                     }
2790                 }
2791             }.bind();
2792         } finally {
2793             restoreCallingIdentity(identityToken);
2794         }
2795     }
2796 
2797     @Override
getAuthToken( IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, final boolean expectActivityLaunch, final Bundle loginOptions)2798     public void getAuthToken(
2799             IAccountManagerResponse response,
2800             final Account account,
2801             final String authTokenType,
2802             final boolean notifyOnAuthFailure,
2803             final boolean expectActivityLaunch,
2804             final Bundle loginOptions) {
2805         Bundle.setDefusable(loginOptions, true);
2806         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2807             Log.v(TAG, "getAuthToken: " + account
2808                     + ", response " + response
2809                     + ", authTokenType " + authTokenType
2810                     + ", notifyOnAuthFailure " + notifyOnAuthFailure
2811                     + ", expectActivityLaunch " + expectActivityLaunch
2812                     + ", caller's uid " + Binder.getCallingUid()
2813                     + ", pid " + Binder.getCallingPid());
2814         }
2815         Preconditions.checkArgument(response != null, "response cannot be null");
2816         try {
2817             if (account == null) {
2818                 Slog.w(TAG, "getAuthToken called with null account");
2819                 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2820                 return;
2821             }
2822             if (authTokenType == null) {
2823                 Slog.w(TAG, "getAuthToken called with null authTokenType");
2824                 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2825                 return;
2826             }
2827         } catch (RemoteException e) {
2828             Slog.w(TAG, "Failed to report error back to the client." + e);
2829             return;
2830         }
2831         int userId = UserHandle.getCallingUserId();
2832         long ident = Binder.clearCallingIdentity();
2833         final UserAccounts accounts;
2834         final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
2835         try {
2836             accounts = getUserAccounts(userId);
2837             authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2838                     AuthenticatorDescription.newKey(account.type), accounts.userId);
2839         } finally {
2840             Binder.restoreCallingIdentity(ident);
2841         }
2842 
2843         final boolean customTokens =
2844                 authenticatorInfo != null && authenticatorInfo.type.customTokens;
2845 
2846         // skip the check if customTokens
2847         final int callerUid = Binder.getCallingUid();
2848         final boolean permissionGranted =
2849                 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
2850 
2851         // Get the calling package. We will use it for the purpose of caching.
2852         final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
2853         List<String> callerOwnedPackageNames;
2854         ident = Binder.clearCallingIdentity();
2855         try {
2856             callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2857         } finally {
2858             Binder.restoreCallingIdentity(ident);
2859         }
2860         if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2861             String msg = String.format(
2862                     "Uid %s is attempting to illegally masquerade as package %s!",
2863                     callerUid,
2864                     callerPkg);
2865             throw new SecurityException(msg);
2866         }
2867 
2868         // let authenticator know the identity of the caller
2869         loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2870         loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
2871 
2872         if (notifyOnAuthFailure) {
2873             loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
2874         }
2875 
2876         long identityToken = clearCallingIdentity();
2877         try {
2878             // Distill the caller's package signatures into a single digest.
2879             final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2880 
2881             // if the caller has permission, do the peek. otherwise go the more expensive
2882             // route of starting a Session
2883             if (!customTokens && permissionGranted) {
2884                 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
2885                 if (authToken != null) {
2886                     Bundle result = new Bundle();
2887                     result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2888                     result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2889                     result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2890                     onResult(response, result);
2891                     return;
2892                 }
2893             }
2894 
2895             if (customTokens) {
2896                 /*
2897                  * Look up tokens in the new cache only if the loginOptions don't have parameters
2898                  * outside of those expected to be injected by the AccountManager, e.g.
2899                  * ANDORID_PACKAGE_NAME.
2900                  */
2901                 String token = readCachedTokenInternal(
2902                         accounts,
2903                         account,
2904                         authTokenType,
2905                         callerPkg,
2906                         callerPkgSigDigest);
2907                 if (token != null) {
2908                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
2909                         Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2910                     }
2911                     Bundle result = new Bundle();
2912                     result.putString(AccountManager.KEY_AUTHTOKEN, token);
2913                     result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2914                     result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2915                     onResult(response, result);
2916                     return;
2917                 }
2918             }
2919 
2920             new Session(
2921                     accounts,
2922                     response,
2923                     account.type,
2924                     expectActivityLaunch,
2925                     false /* stripAuthTokenFromResult */,
2926                     account.name,
2927                     false /* authDetailsRequired */) {
2928                 @Override
2929                 protected String toDebugString(long now) {
2930                     if (loginOptions != null) loginOptions.keySet();
2931                     return super.toDebugString(now) + ", getAuthToken"
2932                             + ", " + account.toSafeString()
2933                             + ", authTokenType " + authTokenType
2934                             + ", loginOptions " + loginOptions
2935                             + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2936                 }
2937 
2938                 @Override
2939                 public void run() throws RemoteException {
2940                     // If the caller doesn't have permission then create and return the
2941                     // "grant permission" intent instead of the "getAuthToken" intent.
2942                     if (!permissionGranted) {
2943                         mAuthenticator.getAuthTokenLabel(this, authTokenType);
2944                     } else {
2945                         mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2946                     }
2947                 }
2948 
2949                 @Override
2950                 public void onResult(Bundle result) {
2951                     Bundle.setDefusable(result, true);
2952                     if (result != null) {
2953                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
2954                             Intent intent = newGrantCredentialsPermissionIntent(
2955                                     account,
2956                                     null,
2957                                     callerUid,
2958                                     new AccountAuthenticatorResponse(this),
2959                                     authTokenType,
2960                                     true);
2961                             Bundle bundle = new Bundle();
2962                             bundle.putParcelable(AccountManager.KEY_INTENT, intent);
2963                             onResult(bundle);
2964                             return;
2965                         }
2966                         String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
2967                         if (authToken != null) {
2968                             String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2969                             String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
2970                             if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
2971                                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
2972                                         "the type and name should not be empty");
2973                                 return;
2974                             }
2975                             Account resultAccount = new Account(name, type);
2976                             if (!customTokens) {
2977                                 saveAuthTokenToDatabase(
2978                                         mAccounts,
2979                                         resultAccount,
2980                                         authTokenType,
2981                                         authToken);
2982                             }
2983                             long expiryMillis = result.getLong(
2984                                     AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2985                             if (customTokens
2986                                     && expiryMillis > System.currentTimeMillis()) {
2987                                 saveCachedToken(
2988                                         mAccounts,
2989                                         account,
2990                                         callerPkg,
2991                                         callerPkgSigDigest,
2992                                         authTokenType,
2993                                         authToken,
2994                                         expiryMillis);
2995                             }
2996                         }
2997 
2998                         Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
2999                         if (intent != null && notifyOnAuthFailure && !customTokens) {
3000                             /*
3001                              * Make sure that the supplied intent is owned by the authenticator
3002                              * giving it to the system. Otherwise a malicious authenticator could
3003                              * have users launching arbitrary activities by tricking users to
3004                              * interact with malicious notifications.
3005                              */
3006                             if (!checkKeyIntent(
3007                                     Binder.getCallingUid(),
3008                                     intent)) {
3009                                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3010                                         "invalid intent in bundle returned");
3011                                 return;
3012                             }
3013                             doNotification(
3014                                     mAccounts,
3015                                     account,
3016                                     result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
3017                                     intent, "android", accounts.userId);
3018                         }
3019                     }
3020                     super.onResult(result);
3021                 }
3022             }.bind();
3023         } finally {
3024             restoreCallingIdentity(identityToken);
3025         }
3026     }
3027 
calculatePackageSignatureDigest(String callerPkg)3028     private byte[] calculatePackageSignatureDigest(String callerPkg) {
3029         MessageDigest digester;
3030         try {
3031             digester = MessageDigest.getInstance("SHA-256");
3032             PackageInfo pkgInfo = mPackageManager.getPackageInfo(
3033                     callerPkg, PackageManager.GET_SIGNATURES);
3034             for (Signature sig : pkgInfo.signatures) {
3035                 digester.update(sig.toByteArray());
3036             }
3037         } catch (NoSuchAlgorithmException x) {
3038             Log.wtf(TAG, "SHA-256 should be available", x);
3039             digester = null;
3040         } catch (NameNotFoundException e) {
3041             Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
3042             digester = null;
3043         }
3044         return (digester == null) ? null : digester.digest();
3045     }
3046 
createNoCredentialsPermissionNotification(Account account, Intent intent, String packageName, int userId)3047     private void createNoCredentialsPermissionNotification(Account account, Intent intent,
3048             String packageName, int userId) {
3049         int uid = intent.getIntExtra(
3050                 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3051         String authTokenType = intent.getStringExtra(
3052                 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
3053         final String titleAndSubtitle =
3054                 mContext.getString(R.string.permission_request_notification_for_app_with_subtitle,
3055                 getApplicationLabel(packageName), account.name);
3056         final int index = titleAndSubtitle.indexOf('\n');
3057         String title = titleAndSubtitle;
3058         String subtitle = "";
3059         if (index > 0) {
3060             title = titleAndSubtitle.substring(0, index);
3061             subtitle = titleAndSubtitle.substring(index + 1);
3062         }
3063         UserHandle user = UserHandle.of(userId);
3064         Context contextForUser = getContextForUser(user);
3065         Notification n =
3066                 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3067                     .setSmallIcon(android.R.drawable.stat_sys_warning)
3068                     .setWhen(0)
3069                     .setColor(contextForUser.getColor(
3070                             com.android.internal.R.color.system_notification_accent_color))
3071                     .setContentTitle(title)
3072                     .setContentText(subtitle)
3073                     .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3074                             PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3075                             null, user))
3076                     .build();
3077         installNotification(getCredentialPermissionNotificationId(
3078                 account, authTokenType, uid), n, "android", user.getIdentifier());
3079     }
3080 
getApplicationLabel(String packageName)3081     private String getApplicationLabel(String packageName) {
3082         try {
3083             return mPackageManager.getApplicationLabel(
3084                     mPackageManager.getApplicationInfo(packageName, 0)).toString();
3085         } catch (PackageManager.NameNotFoundException e) {
3086             return packageName;
3087         }
3088     }
3089 
newGrantCredentialsPermissionIntent(Account account, String packageName, int uid, AccountAuthenticatorResponse response, String authTokenType, boolean startInNewTask)3090     private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3091             int uid, AccountAuthenticatorResponse response, String authTokenType,
3092             boolean startInNewTask) {
3093 
3094         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
3095 
3096         if (startInNewTask) {
3097             // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3098             // Since it was set in Eclair+ we can't change it without breaking apps using
3099             // the intent from a non-Activity context. This is the default behavior.
3100             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3101         }
3102         intent.addCategory(getCredentialPermissionNotificationId(account,
3103                 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
3104         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
3105         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3106         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
3107         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
3108 
3109         return intent;
3110     }
3111 
getCredentialPermissionNotificationId(Account account, String authTokenType, int uid)3112     private NotificationId getCredentialPermissionNotificationId(Account account,
3113             String authTokenType, int uid) {
3114         NotificationId nId;
3115         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
3116         synchronized (accounts.credentialsPermissionNotificationIds) {
3117             final Pair<Pair<Account, String>, Integer> key =
3118                     new Pair<Pair<Account, String>, Integer>(
3119                             new Pair<Account, String>(account, authTokenType), uid);
3120             nId = accounts.credentialsPermissionNotificationIds.get(key);
3121             if (nId == null) {
3122                 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3123                         + ":" + account.hashCode() + ":" + authTokenType.hashCode() + ":" + uid;
3124                 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3125                 nId = new NotificationId(tag, id);
3126                 accounts.credentialsPermissionNotificationIds.put(key, nId);
3127             }
3128         }
3129         return nId;
3130     }
3131 
getSigninRequiredNotificationId(UserAccounts accounts, Account account)3132     private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3133         NotificationId nId;
3134         synchronized (accounts.signinRequiredNotificationIds) {
3135             nId = accounts.signinRequiredNotificationIds.get(account);
3136             if (nId == null) {
3137                 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3138                         + ":" + account.hashCode();
3139                 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3140                 nId = new NotificationId(tag, id);
3141                 accounts.signinRequiredNotificationIds.put(account, nId);
3142             }
3143         }
3144         return nId;
3145     }
3146 
3147     @Override
addAccount(final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn)3148     public void addAccount(final IAccountManagerResponse response, final String accountType,
3149             final String authTokenType, final String[] requiredFeatures,
3150             final boolean expectActivityLaunch, final Bundle optionsIn) {
3151         Bundle.setDefusable(optionsIn, true);
3152         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3153             Log.v(TAG, "addAccount: accountType " + accountType
3154                     + ", response " + response
3155                     + ", authTokenType " + authTokenType
3156                     + ", requiredFeatures " + Arrays.toString(requiredFeatures)
3157                     + ", expectActivityLaunch " + expectActivityLaunch
3158                     + ", caller's uid " + Binder.getCallingUid()
3159                     + ", pid " + Binder.getCallingPid());
3160         }
3161         if (response == null) throw new IllegalArgumentException("response is null");
3162         if (accountType == null) throw new IllegalArgumentException("accountType is null");
3163 
3164         // Is user disallowed from modifying accounts?
3165         final int uid = Binder.getCallingUid();
3166         final int userId = UserHandle.getUserId(uid);
3167         if (!canUserModifyAccounts(userId, uid)) {
3168             try {
3169                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3170                         "User is not allowed to add an account!");
3171             } catch (RemoteException re) {
3172             }
3173             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3174             return;
3175         }
3176         if (!canUserModifyAccountsForType(userId, accountType, uid)) {
3177             try {
3178                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3179                         "User cannot modify accounts of this type (policy).");
3180             } catch (RemoteException re) {
3181             }
3182             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3183                     userId);
3184             return;
3185         }
3186 
3187         final int pid = Binder.getCallingPid();
3188         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3189         options.putInt(AccountManager.KEY_CALLER_UID, uid);
3190         options.putInt(AccountManager.KEY_CALLER_PID, pid);
3191 
3192         int usrId = UserHandle.getCallingUserId();
3193         long identityToken = clearCallingIdentity();
3194         try {
3195             UserAccounts accounts = getUserAccounts(usrId);
3196             logRecordWithUid(
3197                     accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3198                     uid);
3199             new Session(accounts, response, accountType, expectActivityLaunch,
3200                     true /* stripAuthTokenFromResult */, null /* accountName */,
3201                     false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
3202                 @Override
3203                 public void run() throws RemoteException {
3204                     mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3205                             options);
3206                 }
3207 
3208                 @Override
3209                 protected String toDebugString(long now) {
3210                     return super.toDebugString(now) + ", addAccount"
3211                             + ", accountType " + accountType
3212                             + ", requiredFeatures " + Arrays.toString(requiredFeatures);
3213                 }
3214             }.bind();
3215         } finally {
3216             restoreCallingIdentity(identityToken);
3217         }
3218     }
3219 
3220     @Override
addAccountAsUser(final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn, int userId)3221     public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3222             final String authTokenType, final String[] requiredFeatures,
3223             final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
3224         Bundle.setDefusable(optionsIn, true);
3225         int callingUid = Binder.getCallingUid();
3226         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3227             Log.v(TAG, "addAccount: accountType " + accountType
3228                     + ", response " + response
3229                     + ", authTokenType " + authTokenType
3230                     + ", requiredFeatures " + Arrays.toString(requiredFeatures)
3231                     + ", expectActivityLaunch " + expectActivityLaunch
3232                     + ", caller's uid " + Binder.getCallingUid()
3233                     + ", pid " + Binder.getCallingPid()
3234                     + ", for user id " + userId);
3235         }
3236         Preconditions.checkArgument(response != null, "response cannot be null");
3237         Preconditions.checkArgument(accountType != null, "accountType cannot be null");
3238         // Only allow the system process to add accounts of other users
3239         if (isCrossUser(callingUid, userId)) {
3240             throw new SecurityException(
3241                     String.format(
3242                             "User %s trying to add account for %s" ,
3243                             UserHandle.getCallingUserId(),
3244                             userId));
3245         }
3246 
3247         // Is user disallowed from modifying accounts?
3248         if (!canUserModifyAccounts(userId, callingUid)) {
3249             try {
3250                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3251                         "User is not allowed to add an account!");
3252             } catch (RemoteException re) {
3253             }
3254             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3255             return;
3256         }
3257         if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
3258             try {
3259                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3260                         "User cannot modify accounts of this type (policy).");
3261             } catch (RemoteException re) {
3262             }
3263             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3264                     userId);
3265             return;
3266         }
3267 
3268         final int pid = Binder.getCallingPid();
3269         final int uid = Binder.getCallingUid();
3270         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3271         options.putInt(AccountManager.KEY_CALLER_UID, uid);
3272         options.putInt(AccountManager.KEY_CALLER_PID, pid);
3273 
3274         long identityToken = clearCallingIdentity();
3275         try {
3276             UserAccounts accounts = getUserAccounts(userId);
3277             logRecordWithUid(
3278                     accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3279                     uid);
3280             new Session(accounts, response, accountType, expectActivityLaunch,
3281                     true /* stripAuthTokenFromResult */, null /* accountName */,
3282                     false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
3283                 @Override
3284                 public void run() throws RemoteException {
3285                     mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3286                             options);
3287                 }
3288 
3289                 @Override
3290                 protected String toDebugString(long now) {
3291                     return super.toDebugString(now) + ", addAccount"
3292                             + ", accountType " + accountType
3293                             + ", requiredFeatures "
3294                             + (requiredFeatures != null
3295                               ? TextUtils.join(",", requiredFeatures)
3296                               : null);
3297                 }
3298             }.bind();
3299         } finally {
3300             restoreCallingIdentity(identityToken);
3301         }
3302     }
3303 
3304     @Override
startAddAccountSession( final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn)3305     public void startAddAccountSession(
3306             final IAccountManagerResponse response,
3307             final String accountType,
3308             final String authTokenType,
3309             final String[] requiredFeatures,
3310             final boolean expectActivityLaunch,
3311             final Bundle optionsIn) {
3312         Bundle.setDefusable(optionsIn, true);
3313         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3314             Log.v(TAG,
3315                     "startAddAccountSession: accountType " + accountType
3316                     + ", response " + response
3317                     + ", authTokenType " + authTokenType
3318                     + ", requiredFeatures " + Arrays.toString(requiredFeatures)
3319                     + ", expectActivityLaunch " + expectActivityLaunch
3320                     + ", caller's uid " + Binder.getCallingUid()
3321                     + ", pid " + Binder.getCallingPid());
3322         }
3323         Preconditions.checkArgument(response != null, "response cannot be null");
3324         Preconditions.checkArgument(accountType != null, "accountType cannot be null");
3325 
3326         final int uid = Binder.getCallingUid();
3327         final int userId = UserHandle.getUserId(uid);
3328         if (!canUserModifyAccounts(userId, uid)) {
3329             try {
3330                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3331                         "User is not allowed to add an account!");
3332             } catch (RemoteException re) {
3333             }
3334             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3335             return;
3336         }
3337         if (!canUserModifyAccountsForType(userId, accountType, uid)) {
3338             try {
3339                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3340                         "User cannot modify accounts of this type (policy).");
3341             } catch (RemoteException re) {
3342             }
3343             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3344                     userId);
3345             return;
3346         }
3347         final int pid = Binder.getCallingPid();
3348         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3349         options.putInt(AccountManager.KEY_CALLER_UID, uid);
3350         options.putInt(AccountManager.KEY_CALLER_PID, pid);
3351 
3352         // Check to see if the Password should be included to the caller.
3353         String callerPkg = options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3354         boolean isPasswordForwardingAllowed = checkPermissionAndNote(
3355                 callerPkg, uid, Manifest.permission.GET_PASSWORD);
3356 
3357         long identityToken = clearCallingIdentity();
3358         try {
3359             UserAccounts accounts = getUserAccounts(userId);
3360             logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3361                     AccountsDb.TABLE_ACCOUNTS, uid);
3362             new StartAccountSession(
3363                     accounts,
3364                     response,
3365                     accountType,
3366                     expectActivityLaunch,
3367                     null /* accountName */,
3368                     false /* authDetailsRequired */,
3369                     true /* updateLastAuthenticationTime */,
3370                     isPasswordForwardingAllowed) {
3371                 @Override
3372                 public void run() throws RemoteException {
3373                     mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3374                             requiredFeatures, options);
3375                 }
3376 
3377                 @Override
3378                 protected String toDebugString(long now) {
3379                     String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3380                     return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3381                             + accountType + ", requiredFeatures "
3382                             + (requiredFeatures != null ? requiredFeaturesStr : null);
3383                 }
3384             }.bind();
3385         } finally {
3386             restoreCallingIdentity(identityToken);
3387         }
3388     }
3389 
3390     /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3391     private abstract class StartAccountSession extends Session {
3392 
3393         private final boolean mIsPasswordForwardingAllowed;
3394 
StartAccountSession( UserAccounts accounts, IAccountManagerResponse response, String accountType, boolean expectActivityLaunch, String accountName, boolean authDetailsRequired, boolean updateLastAuthenticationTime, boolean isPasswordForwardingAllowed)3395         public StartAccountSession(
3396                 UserAccounts accounts,
3397                 IAccountManagerResponse response,
3398                 String accountType,
3399                 boolean expectActivityLaunch,
3400                 String accountName,
3401                 boolean authDetailsRequired,
3402                 boolean updateLastAuthenticationTime,
3403                 boolean isPasswordForwardingAllowed) {
3404             super(accounts, response, accountType, expectActivityLaunch,
3405                     true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3406                     updateLastAuthenticationTime);
3407             mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
3408         }
3409 
3410         @Override
onResult(Bundle result)3411         public void onResult(Bundle result) {
3412             Bundle.setDefusable(result, true);
3413             mNumResults++;
3414             Intent intent = null;
3415             if (result != null
3416                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
3417                 if (!checkKeyIntent(
3418                         Binder.getCallingUid(),
3419                         intent)) {
3420                     onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3421                             "invalid intent in bundle returned");
3422                     return;
3423                 }
3424             }
3425             IAccountManagerResponse response;
3426             if (mExpectActivityLaunch && result != null
3427                     && result.containsKey(AccountManager.KEY_INTENT)) {
3428                 response = mResponse;
3429             } else {
3430                 response = getResponseAndClose();
3431             }
3432             if (response == null) {
3433                 return;
3434             }
3435             if (result == null) {
3436                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3437                     Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3438                             + response);
3439                 }
3440                 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3441                         "null bundle returned");
3442                 return;
3443             }
3444 
3445             if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3446                 // All AccountManager error codes are greater
3447                 // than 0
3448                 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3449                         result.getString(AccountManager.KEY_ERROR_MESSAGE));
3450                 return;
3451             }
3452 
3453             // Omit passwords if the caller isn't permitted to see them.
3454             if (!mIsPasswordForwardingAllowed) {
3455                 result.remove(AccountManager.KEY_PASSWORD);
3456             }
3457 
3458             // Strip auth token from result.
3459             result.remove(AccountManager.KEY_AUTHTOKEN);
3460 
3461             if (Log.isLoggable(TAG, Log.VERBOSE)) {
3462                 Log.v(TAG,
3463                         getClass().getSimpleName() + " calling onResult() on response " + response);
3464             }
3465 
3466             // Get the session bundle created by authenticator. The
3467             // bundle contains data necessary for finishing the session
3468             // later. The session bundle will be encrypted here and
3469             // decrypted later when trying to finish the session.
3470             Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3471             if (sessionBundle != null) {
3472                 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3473                 if (TextUtils.isEmpty(accountType)
3474                         || !mAccountType.equalsIgnoreCase(accountType)) {
3475                     Log.w(TAG, "Account type in session bundle doesn't match request.");
3476                 }
3477                 // Add accountType info to session bundle. This will
3478                 // override any value set by authenticator.
3479                 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3480 
3481                 // Encrypt session bundle before returning to caller.
3482                 try {
3483                     CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3484                     Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3485                     result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3486                 } catch (GeneralSecurityException e) {
3487                     if (Log.isLoggable(TAG, Log.DEBUG)) {
3488                         Log.v(TAG, "Failed to encrypt session bundle!", e);
3489                     }
3490                     sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3491                             "failed to encrypt session bundle");
3492                     return;
3493                 }
3494             }
3495 
3496             sendResponse(response, result);
3497         }
3498     }
3499 
3500     @Override
finishSessionAsUser(IAccountManagerResponse response, @NonNull Bundle sessionBundle, boolean expectActivityLaunch, Bundle appInfo, int userId)3501     public void finishSessionAsUser(IAccountManagerResponse response,
3502             @NonNull Bundle sessionBundle,
3503             boolean expectActivityLaunch,
3504             Bundle appInfo,
3505             int userId) {
3506         Bundle.setDefusable(sessionBundle, true);
3507         int callingUid = Binder.getCallingUid();
3508         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3509             Log.v(TAG,
3510                     "finishSession: response "+ response
3511                             + ", expectActivityLaunch " + expectActivityLaunch
3512                             + ", caller's uid " + callingUid
3513                             + ", caller's user id " + UserHandle.getCallingUserId()
3514                             + ", pid " + Binder.getCallingPid()
3515                             + ", for user id " + userId);
3516         }
3517         Preconditions.checkArgument(response != null, "response cannot be null");
3518         // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3519         // Account type is added to it before encryption.
3520         if (sessionBundle == null || sessionBundle.size() == 0) {
3521             throw new IllegalArgumentException("sessionBundle is empty");
3522         }
3523 
3524         // Only allow the system process to finish session for other users.
3525         if (isCrossUser(callingUid, userId)) {
3526             throw new SecurityException(
3527                     String.format(
3528                             "User %s trying to finish session for %s without cross user permission",
3529                             UserHandle.getCallingUserId(),
3530                             userId));
3531         }
3532 
3533         if (!canUserModifyAccounts(userId, callingUid)) {
3534             sendErrorResponse(response,
3535                     AccountManager.ERROR_CODE_USER_RESTRICTED,
3536                     "User is not allowed to add an account!");
3537             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3538             return;
3539         }
3540 
3541         final int pid = Binder.getCallingPid();
3542         final Bundle decryptedBundle;
3543         final String accountType;
3544         // First decrypt session bundle to get account type for checking permission.
3545         try {
3546             CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3547             decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3548             if (decryptedBundle == null) {
3549                 sendErrorResponse(
3550                         response,
3551                         AccountManager.ERROR_CODE_BAD_REQUEST,
3552                         "failed to decrypt session bundle");
3553                 return;
3554             }
3555             accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3556             // Account type cannot be null. This should not happen if session bundle was created
3557             // properly by #StartAccountSession.
3558             if (TextUtils.isEmpty(accountType)) {
3559                 sendErrorResponse(
3560                         response,
3561                         AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3562                         "accountType is empty");
3563                 return;
3564             }
3565 
3566             // If by any chances, decryptedBundle contains colliding keys with
3567             // system info
3568             // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3569             // update credentials flow, we should replace with the new values of the current call.
3570             if (appInfo != null) {
3571                 decryptedBundle.putAll(appInfo);
3572             }
3573 
3574             // Add info that may be used by add account or update credentials flow.
3575             decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
3576             decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3577         } catch (GeneralSecurityException e) {
3578             if (Log.isLoggable(TAG, Log.DEBUG)) {
3579                 Log.v(TAG, "Failed to decrypt session bundle!", e);
3580             }
3581             sendErrorResponse(
3582                     response,
3583                     AccountManager.ERROR_CODE_BAD_REQUEST,
3584                     "failed to decrypt session bundle");
3585             return;
3586         }
3587 
3588         if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
3589             sendErrorResponse(
3590                     response,
3591                     AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3592                     "User cannot modify accounts of this type (policy).");
3593             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3594                     userId);
3595             return;
3596         }
3597 
3598         long identityToken = clearCallingIdentity();
3599         try {
3600             UserAccounts accounts = getUserAccounts(userId);
3601             logRecordWithUid(
3602                     accounts,
3603                     AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3604                     AccountsDb.TABLE_ACCOUNTS,
3605                     callingUid);
3606             new Session(
3607                     accounts,
3608                     response,
3609                     accountType,
3610                     expectActivityLaunch,
3611                     true /* stripAuthTokenFromResult */,
3612                     null /* accountName */,
3613                     false /* authDetailsRequired */,
3614                     true /* updateLastAuthenticationTime */) {
3615                 @Override
3616                 public void run() throws RemoteException {
3617                     mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3618                 }
3619 
3620                 @Override
3621                 protected String toDebugString(long now) {
3622                     return super.toDebugString(now)
3623                             + ", finishSession"
3624                             + ", accountType " + accountType;
3625                 }
3626             }.bind();
3627         } finally {
3628             restoreCallingIdentity(identityToken);
3629         }
3630     }
3631 
showCantAddAccount(int errorCode, int userId)3632     private void showCantAddAccount(int errorCode, int userId) {
3633         final DevicePolicyManagerInternal dpmi =
3634                 LocalServices.getService(DevicePolicyManagerInternal.class);
3635         Intent intent = null;
3636         if (dpmi == null) {
3637             intent = getDefaultCantAddAccountIntent(errorCode);
3638         } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
3639             intent = dpmi.createUserRestrictionSupportIntent(userId,
3640                     UserManager.DISALLOW_MODIFY_ACCOUNTS);
3641         } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3642             intent = dpmi.createShowAdminSupportIntent(userId, false);
3643         }
3644         if (intent == null) {
3645             intent = getDefaultCantAddAccountIntent(errorCode);
3646         }
3647         long identityToken = clearCallingIdentity();
3648         try {
3649             mContext.startActivityAsUser(intent, new UserHandle(userId));
3650         } finally {
3651             restoreCallingIdentity(identityToken);
3652         }
3653     }
3654 
3655     /**
3656      * Called when we don't know precisely who is preventing us from adding an account.
3657      */
getDefaultCantAddAccountIntent(int errorCode)3658     private Intent getDefaultCantAddAccountIntent(int errorCode) {
3659         Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3660         cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3661         cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3662         return cantAddAccount;
3663     }
3664 
3665     @Override
confirmCredentialsAsUser( IAccountManagerResponse response, final Account account, final Bundle options, final boolean expectActivityLaunch, int userId)3666     public void confirmCredentialsAsUser(
3667             IAccountManagerResponse response,
3668             final Account account,
3669             final Bundle options,
3670             final boolean expectActivityLaunch,
3671             int userId) {
3672         Bundle.setDefusable(options, true);
3673         int callingUid = Binder.getCallingUid();
3674         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3675             Log.v(TAG, "confirmCredentials: " + account
3676                     + ", response " + response
3677                     + ", expectActivityLaunch " + expectActivityLaunch
3678                     + ", caller's uid " + callingUid
3679                     + ", pid " + Binder.getCallingPid());
3680         }
3681         // Only allow the system process to read accounts of other users
3682         if (isCrossUser(callingUid, userId)) {
3683             throw new SecurityException(
3684                     String.format(
3685                             "User %s trying to confirm account credentials for %s" ,
3686                             UserHandle.getCallingUserId(),
3687                             userId));
3688         }
3689         if (response == null) throw new IllegalArgumentException("response is null");
3690         if (account == null) throw new IllegalArgumentException("account is null");
3691         long identityToken = clearCallingIdentity();
3692         try {
3693             UserAccounts accounts = getUserAccounts(userId);
3694             new Session(accounts, response, account.type, expectActivityLaunch,
3695                     true /* stripAuthTokenFromResult */, account.name,
3696                     true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
3697                 @Override
3698                 public void run() throws RemoteException {
3699                     mAuthenticator.confirmCredentials(this, account, options);
3700                 }
3701                 @Override
3702                 protected String toDebugString(long now) {
3703                     return super.toDebugString(now) + ", confirmCredentials"
3704                             + ", " + account.toSafeString();
3705                 }
3706             }.bind();
3707         } finally {
3708             restoreCallingIdentity(identityToken);
3709         }
3710     }
3711 
3712     @Override
updateCredentials(IAccountManagerResponse response, final Account account, final String authTokenType, final boolean expectActivityLaunch, final Bundle loginOptions)3713     public void updateCredentials(IAccountManagerResponse response, final Account account,
3714             final String authTokenType, final boolean expectActivityLaunch,
3715             final Bundle loginOptions) {
3716         Bundle.setDefusable(loginOptions, true);
3717         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3718             Log.v(TAG, "updateCredentials: " + account
3719                     + ", response " + response
3720                     + ", authTokenType " + authTokenType
3721                     + ", expectActivityLaunch " + expectActivityLaunch
3722                     + ", caller's uid " + Binder.getCallingUid()
3723                     + ", pid " + Binder.getCallingPid());
3724         }
3725         if (response == null) throw new IllegalArgumentException("response is null");
3726         if (account == null) throw new IllegalArgumentException("account is null");
3727         int userId = UserHandle.getCallingUserId();
3728         long identityToken = clearCallingIdentity();
3729         try {
3730             UserAccounts accounts = getUserAccounts(userId);
3731             new Session(accounts, response, account.type, expectActivityLaunch,
3732                     true /* stripAuthTokenFromResult */, account.name,
3733                     false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
3734                 @Override
3735                 public void run() throws RemoteException {
3736                     mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3737                 }
3738                 @Override
3739                 protected String toDebugString(long now) {
3740                     if (loginOptions != null) loginOptions.keySet();
3741                     return super.toDebugString(now) + ", updateCredentials"
3742                             + ", " + account.toSafeString()
3743                             + ", authTokenType " + authTokenType
3744                             + ", loginOptions " + loginOptions;
3745                 }
3746             }.bind();
3747         } finally {
3748             restoreCallingIdentity(identityToken);
3749         }
3750     }
3751 
3752     @Override
startUpdateCredentialsSession( IAccountManagerResponse response, final Account account, final String authTokenType, final boolean expectActivityLaunch, final Bundle loginOptions)3753     public void startUpdateCredentialsSession(
3754             IAccountManagerResponse response,
3755             final Account account,
3756             final String authTokenType,
3757             final boolean expectActivityLaunch,
3758             final Bundle loginOptions) {
3759         Bundle.setDefusable(loginOptions, true);
3760         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3761             Log.v(TAG,
3762                     "startUpdateCredentialsSession: " + account + ", response " + response
3763                             + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3764                             + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3765                             + ", pid " + Binder.getCallingPid());
3766         }
3767         if (response == null) {
3768             throw new IllegalArgumentException("response is null");
3769         }
3770         if (account == null) {
3771             throw new IllegalArgumentException("account is null");
3772         }
3773 
3774         final int uid = Binder.getCallingUid();
3775         int userId = UserHandle.getCallingUserId();
3776 
3777         // Check to see if the Password should be included to the caller.
3778         String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3779         boolean isPasswordForwardingAllowed = checkPermissionAndNote(
3780                 callerPkg, uid, Manifest.permission.GET_PASSWORD);
3781 
3782         long identityToken = clearCallingIdentity();
3783         try {
3784             UserAccounts accounts = getUserAccounts(userId);
3785             new StartAccountSession(
3786                     accounts,
3787                     response,
3788                     account.type,
3789                     expectActivityLaunch,
3790                     account.name,
3791                     false /* authDetailsRequired */,
3792                     true /* updateLastCredentialTime */,
3793                     isPasswordForwardingAllowed) {
3794                 @Override
3795                 public void run() throws RemoteException {
3796                     mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3797                             loginOptions);
3798                 }
3799 
3800                 @Override
3801                 protected String toDebugString(long now) {
3802                     if (loginOptions != null)
3803                         loginOptions.keySet();
3804                     return super.toDebugString(now)
3805                             + ", startUpdateCredentialsSession"
3806                             + ", " + account.toSafeString()
3807                             + ", authTokenType " + authTokenType
3808                             + ", loginOptions " + loginOptions;
3809                 }
3810             }.bind();
3811         } finally {
3812             restoreCallingIdentity(identityToken);
3813         }
3814     }
3815 
3816     @Override
isCredentialsUpdateSuggested( IAccountManagerResponse response, final Account account, final String statusToken)3817     public void isCredentialsUpdateSuggested(
3818             IAccountManagerResponse response,
3819             final Account account,
3820             final String statusToken) {
3821         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3822             Log.v(TAG,
3823                     "isCredentialsUpdateSuggested: " + account + ", response " + response
3824                             + ", caller's uid " + Binder.getCallingUid()
3825                             + ", pid " + Binder.getCallingPid());
3826         }
3827         if (response == null) {
3828             throw new IllegalArgumentException("response is null");
3829         }
3830         if (account == null) {
3831             throw new IllegalArgumentException("account is null");
3832         }
3833         if (TextUtils.isEmpty(statusToken)) {
3834             throw new IllegalArgumentException("status token is empty");
3835         }
3836 
3837         int usrId = UserHandle.getCallingUserId();
3838         long identityToken = clearCallingIdentity();
3839         try {
3840             UserAccounts accounts = getUserAccounts(usrId);
3841             new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3842                     false /* stripAuthTokenFromResult */, account.name,
3843                     false /* authDetailsRequired */) {
3844                 @Override
3845                 protected String toDebugString(long now) {
3846                     return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3847                             + ", " + account.toSafeString();
3848                 }
3849 
3850                 @Override
3851                 public void run() throws RemoteException {
3852                     mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3853                 }
3854 
3855                 @Override
3856                 public void onResult(Bundle result) {
3857                     Bundle.setDefusable(result, true);
3858                     IAccountManagerResponse response = getResponseAndClose();
3859                     if (response == null) {
3860                         return;
3861                     }
3862 
3863                     if (result == null) {
3864                         sendErrorResponse(
3865                                 response,
3866                                 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3867                                 "null bundle");
3868                         return;
3869                     }
3870 
3871                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
3872                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3873                                 + response);
3874                     }
3875                     // Check to see if an error occurred. We know if an error occurred because all
3876                     // error codes are greater than 0.
3877                     if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3878                         sendErrorResponse(response,
3879                                 result.getInt(AccountManager.KEY_ERROR_CODE),
3880                                 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3881                         return;
3882                     }
3883                     if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3884                         sendErrorResponse(
3885                                 response,
3886                                 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3887                                 "no result in response");
3888                         return;
3889                     }
3890                     final Bundle newResult = new Bundle();
3891                     newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3892                             result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3893                     sendResponse(response, newResult);
3894                 }
3895             }.bind();
3896         } finally {
3897             restoreCallingIdentity(identityToken);
3898         }
3899     }
3900 
3901     @Override
editProperties(IAccountManagerResponse response, final String accountType, final boolean expectActivityLaunch)3902     public void editProperties(IAccountManagerResponse response, final String accountType,
3903             final boolean expectActivityLaunch) {
3904         final int callingUid = Binder.getCallingUid();
3905         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3906             Log.v(TAG, "editProperties: accountType " + accountType
3907                     + ", response " + response
3908                     + ", expectActivityLaunch " + expectActivityLaunch
3909                     + ", caller's uid " + callingUid
3910                     + ", pid " + Binder.getCallingPid());
3911         }
3912         if (response == null) throw new IllegalArgumentException("response is null");
3913         if (accountType == null) throw new IllegalArgumentException("accountType is null");
3914         int userId = UserHandle.getCallingUserId();
3915         if (!isAccountManagedByCaller(accountType, callingUid, userId)
3916                 && !isSystemUid(callingUid)) {
3917             String msg = String.format(
3918                     "uid %s cannot edit authenticator properites for account type: %s",
3919                     callingUid,
3920                     accountType);
3921             throw new SecurityException(msg);
3922         }
3923         long identityToken = clearCallingIdentity();
3924         try {
3925             UserAccounts accounts = getUserAccounts(userId);
3926             new Session(accounts, response, accountType, expectActivityLaunch,
3927                     true /* stripAuthTokenFromResult */, null /* accountName */,
3928                     false /* authDetailsRequired */) {
3929                 @Override
3930                 public void run() throws RemoteException {
3931                     mAuthenticator.editProperties(this, mAccountType);
3932                 }
3933                 @Override
3934                 protected String toDebugString(long now) {
3935                     return super.toDebugString(now) + ", editProperties"
3936                             + ", accountType " + accountType;
3937                 }
3938             }.bind();
3939         } finally {
3940             restoreCallingIdentity(identityToken);
3941         }
3942     }
3943 
3944     @Override
hasAccountAccess(@onNull Account account, @NonNull String packageName, @NonNull UserHandle userHandle)3945     public boolean hasAccountAccess(@NonNull Account account,  @NonNull String packageName,
3946             @NonNull UserHandle userHandle) {
3947         if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
3948             throw new SecurityException("Can be called only by system UID");
3949         }
3950         Objects.requireNonNull(account, "account cannot be null");
3951         Objects.requireNonNull(packageName, "packageName cannot be null");
3952         Objects.requireNonNull(userHandle, "userHandle cannot be null");
3953 
3954         final int userId = userHandle.getIdentifier();
3955 
3956         Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3957 
3958         try {
3959             int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3960             return hasAccountAccess(account, packageName, uid);
3961         } catch (NameNotFoundException e) {
3962             Log.d(TAG, "Package not found " + e.getMessage());
3963             return false;
3964         }
3965     }
3966 
3967     // Returns package with oldest target SDK for given UID.
getPackageNameForUid(int uid)3968     private String getPackageNameForUid(int uid) {
3969         String[] packageNames = mPackageManager.getPackagesForUid(uid);
3970         if (ArrayUtils.isEmpty(packageNames)) {
3971             return null;
3972         }
3973         String packageName = packageNames[0];
3974         if (packageNames.length == 1) {
3975             return packageName;
3976         }
3977         // Due to visibility changes we want to use package with oldest target SDK
3978         int oldestVersion = Integer.MAX_VALUE;
3979         for (String name : packageNames) {
3980             try {
3981                 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3982                 if (applicationInfo != null) {
3983                     int version = applicationInfo.targetSdkVersion;
3984                     if (version < oldestVersion) {
3985                         oldestVersion = version;
3986                         packageName = name;
3987                     }
3988                 }
3989             } catch (NameNotFoundException e) {
3990                 // skip
3991             }
3992         }
3993         return packageName;
3994     }
3995 
hasAccountAccess(@onNull Account account, @Nullable String packageName, int uid)3996     private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3997             int uid) {
3998         if (packageName == null) {
3999             packageName = getPackageNameForUid(uid);
4000             if (packageName == null) {
4001                 return false;
4002             }
4003         }
4004 
4005         // Use null token which means any token. Having a token means the package
4006         // is trusted by the authenticator, hence it is fine to access the account.
4007         if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
4008             return true;
4009         }
4010         // In addition to the permissions required to get an auth token we also allow
4011         // the account to be accessed by apps for which user or authenticator granted visibility.
4012 
4013         int visibility = resolveAccountVisibility(account, packageName,
4014             getUserAccounts(UserHandle.getUserId(uid)));
4015         return (visibility == AccountManager.VISIBILITY_VISIBLE
4016             || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
4017     }
4018 
4019     @Override
createRequestAccountAccessIntentSenderAsUser(@onNull Account account, @NonNull String packageName, @NonNull UserHandle userHandle)4020     public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
4021             @NonNull String packageName, @NonNull UserHandle userHandle) {
4022         if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
4023             throw new SecurityException("Can be called only by system UID");
4024         }
4025 
4026         Objects.requireNonNull(account, "account cannot be null");
4027         Objects.requireNonNull(packageName, "packageName cannot be null");
4028         Objects.requireNonNull(userHandle, "userHandle cannot be null");
4029 
4030         final int userId = userHandle.getIdentifier();
4031 
4032         Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
4033 
4034         final int uid;
4035         try {
4036             uid = mPackageManager.getPackageUidAsUser(packageName, userId);
4037         } catch (NameNotFoundException e) {
4038             Slog.e(TAG, "Unknown package " + packageName);
4039             return null;
4040         }
4041 
4042         Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
4043 
4044         final long identity = Binder.clearCallingIdentity();
4045         try {
4046             return PendingIntent.getActivityAsUser(
4047                     mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
4048                             | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
4049                     null, new UserHandle(userId)).getIntentSender();
4050         } finally {
4051             Binder.restoreCallingIdentity(identity);
4052         }
4053     }
4054 
newRequestAccountAccessIntent(Account account, String packageName, int uid, RemoteCallback callback)4055     private Intent newRequestAccountAccessIntent(Account account, String packageName,
4056             int uid, RemoteCallback callback) {
4057         return newGrantCredentialsPermissionIntent(account, packageName, uid,
4058                 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
4059             @Override
4060             public void onResult(Bundle value) throws RemoteException {
4061                 handleAuthenticatorResponse(true);
4062             }
4063 
4064             @Override
4065             public void onRequestContinued() {
4066                 /* ignore */
4067             }
4068 
4069             @Override
4070             public void onError(int errorCode, String errorMessage) throws RemoteException {
4071                 handleAuthenticatorResponse(false);
4072             }
4073 
4074             private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4075                 cancelNotification(getCredentialPermissionNotificationId(account,
4076                         AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid),
4077                         UserHandle.getUserHandleForUid(uid));
4078                 if (callback != null) {
4079                     Bundle result = new Bundle();
4080                     result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4081                     callback.sendResult(result);
4082                 }
4083             }
4084         }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
4085     }
4086 
4087     @Override
4088     public boolean someUserHasAccount(@NonNull final Account account) {
4089         if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4090             throw new SecurityException("Only system can check for accounts across users");
4091         }
4092         final long token = Binder.clearCallingIdentity();
4093         try {
4094             AccountAndUser[] allAccounts = getAllAccounts();
4095             for (int i = allAccounts.length - 1; i >= 0; i--) {
4096                 if (allAccounts[i].account.equals(account)) {
4097                     return true;
4098                 }
4099             }
4100             return false;
4101         } finally {
4102             Binder.restoreCallingIdentity(token);
4103         }
4104     }
4105 
4106     private class GetAccountsByTypeAndFeatureSession extends Session {
4107         private final String[] mFeatures;
4108         private volatile Account[] mAccountsOfType = null;
4109         private volatile ArrayList<Account> mAccountsWithFeatures = null;
4110         private volatile int mCurrentAccount = 0;
4111         private final int mCallingUid;
4112         private final String mPackageName;
4113         private final boolean mIncludeManagedNotVisible;
4114 
4115         public GetAccountsByTypeAndFeatureSession(
4116                 UserAccounts accounts,
4117                 IAccountManagerResponse response,
4118                 String type,
4119                 String[] features,
4120                 int callingUid,
4121                 String packageName,
4122                 boolean includeManagedNotVisible) {
4123             super(accounts, response, type, false /* expectActivityLaunch */,
4124                     true /* stripAuthTokenFromResult */, null /* accountName */,
4125                     false /* authDetailsRequired */);
4126             mCallingUid = callingUid;
4127             mFeatures = features;
4128             mPackageName = packageName;
4129             mIncludeManagedNotVisible = includeManagedNotVisible;
4130         }
4131 
4132         @Override
4133         public void run() throws RemoteException {
4134             mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
4135                     mCallingUid, mPackageName, mIncludeManagedNotVisible);
4136             // check whether each account matches the requested features
4137             mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
4138             mCurrentAccount = 0;
4139 
4140             checkAccount();
4141         }
4142 
4143         public void checkAccount() {
4144             if (mCurrentAccount >= mAccountsOfType.length) {
4145                 sendResult();
4146                 return;
4147             }
4148 
4149             final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4150             if (accountAuthenticator == null) {
4151                 // It is possible that the authenticator has died, which is indicated by
4152                 // mAuthenticator being set to null. If this happens then just abort.
4153                 // There is no need to send back a result or error in this case since
4154                 // that already happened when mAuthenticator was cleared.
4155                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4156                     Log.v(TAG, "checkAccount: aborting session since we are no longer"
4157                             + " connected to the authenticator, " + toDebugString());
4158                 }
4159                 return;
4160             }
4161             try {
4162                 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
4163             } catch (RemoteException e) {
4164                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
4165             }
4166         }
4167 
4168         @Override
4169         public void onResult(Bundle result) {
4170             Bundle.setDefusable(result, true);
4171             mNumResults++;
4172             if (result == null) {
4173                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
4174                 return;
4175             }
4176             if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
4177                 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4178             }
4179             mCurrentAccount++;
4180             checkAccount();
4181         }
4182 
4183         public void sendResult() {
4184             IAccountManagerResponse response = getResponseAndClose();
4185             if (response != null) {
4186                 try {
4187                     Account[] accounts = new Account[mAccountsWithFeatures.size()];
4188                     for (int i = 0; i < accounts.length; i++) {
4189                         accounts[i] = mAccountsWithFeatures.get(i);
4190                     }
4191                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4192                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4193                                 + response);
4194                     }
4195                     Bundle result = new Bundle();
4196                     result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4197                     response.onResult(result);
4198                 } catch (RemoteException e) {
4199                     // if the caller is dead then there is no one to care about remote exceptions
4200                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4201                         Log.v(TAG, "failure while notifying response", e);
4202                     }
4203                 }
4204             }
4205         }
4206 
4207         @Override
4208         protected String toDebugString(long now) {
4209             return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4210                     + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4211         }
4212     }
4213 
4214     /**
4215      * Returns the accounts visible to the client within the context of a specific user
4216      * @hide
4217      */
4218     @NonNull
4219     public Account[] getAccounts(int userId, String opPackageName) {
4220         int callingUid = Binder.getCallingUid();
4221         mAppOpsManager.checkPackage(callingUid, opPackageName);
4222         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4223                 opPackageName);
4224         if (visibleAccountTypes.isEmpty()) {
4225             return EMPTY_ACCOUNT_ARRAY;
4226         }
4227         long identityToken = clearCallingIdentity();
4228         try {
4229             UserAccounts accounts = getUserAccounts(userId);
4230             return getAccountsInternal(
4231                     accounts,
4232                     callingUid,
4233                     opPackageName,
4234                     visibleAccountTypes,
4235                     false /* includeUserManagedNotVisible */);
4236         } finally {
4237             restoreCallingIdentity(identityToken);
4238         }
4239     }
4240 
4241     /**
4242      * Returns accounts for all running users, ignores visibility values.
4243      *
4244      * @hide
4245      */
4246     @NonNull
4247     public AccountAndUser[] getRunningAccounts() {
4248         final int[] runningUserIds;
4249         try {
4250             runningUserIds = ActivityManager.getService().getRunningUserIds();
4251         } catch (RemoteException e) {
4252             // Running in system_server; should never happen
4253             throw new RuntimeException(e);
4254         }
4255         return getAccounts(runningUserIds);
4256     }
4257 
4258     /**
4259      * Returns accounts for all users, ignores visibility values.
4260      *
4261      * @hide
4262      */
4263     @NonNull
4264     public AccountAndUser[] getAllAccounts() {
4265         final List<UserInfo> users = getUserManager().getUsers(true);
4266         final int[] userIds = new int[users.size()];
4267         for (int i = 0; i < userIds.length; i++) {
4268             userIds[i] = users.get(i).id;
4269         }
4270         return getAccounts(userIds);
4271     }
4272 
4273     @NonNull
4274     private AccountAndUser[] getAccounts(int[] userIds) {
4275         final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
4276         for (int userId : userIds) {
4277             UserAccounts userAccounts = getUserAccounts(userId);
4278             if (userAccounts == null) continue;
4279             Account[] accounts = getAccountsFromCache(
4280                     userAccounts,
4281                     null /* type */,
4282                     Binder.getCallingUid(),
4283                     null /* packageName */,
4284                     false /* include managed not visible*/);
4285             for (Account account : accounts) {
4286                 runningAccounts.add(new AccountAndUser(account, userId));
4287             }
4288         }
4289 
4290         AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4291         return runningAccounts.toArray(accountsArray);
4292     }
4293 
4294     @Override
4295     @NonNull
4296     public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
4297         int callingUid = Binder.getCallingUid();
4298         mAppOpsManager.checkPackage(callingUid, opPackageName);
4299         return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
4300                 opPackageName, false /* includeUserManagedNotVisible */);
4301     }
4302 
4303     @NonNull
4304     private Account[] getAccountsAsUserForPackage(
4305             String type,
4306             int userId,
4307             String callingPackage,
4308             int packageUid,
4309             String opPackageName,
4310             boolean includeUserManagedNotVisible) {
4311         int callingUid = Binder.getCallingUid();
4312         // Only allow the system process to read accounts of other users
4313         if (userId != UserHandle.getCallingUserId()
4314                 && callingUid != Process.SYSTEM_UID
4315                 && mContext.checkCallingOrSelfPermission(
4316                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4317                     != PackageManager.PERMISSION_GRANTED) {
4318             throw new SecurityException("User " + UserHandle.getCallingUserId()
4319                     + " trying to get account for " + userId);
4320         }
4321 
4322         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4323             Log.v(TAG, "getAccounts: accountType " + type
4324                     + ", caller's uid " + Binder.getCallingUid()
4325                     + ", pid " + Binder.getCallingPid());
4326         }
4327 
4328         // If the original calling app was using account choosing activity
4329         // provided by the framework or authenticator we'll passing in
4330         // the original caller's uid here, which is what should be used for filtering.
4331         List<String> managedTypes =
4332                 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4333         if (packageUid != -1 &&
4334                 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4335                 || (type != null && managedTypes.contains(type))))) {
4336             callingUid = packageUid;
4337             opPackageName = callingPackage;
4338         }
4339         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4340                 opPackageName);
4341         if (visibleAccountTypes.isEmpty()
4342                 || (type != null && !visibleAccountTypes.contains(type))) {
4343             return EMPTY_ACCOUNT_ARRAY;
4344         } else if (visibleAccountTypes.contains(type)) {
4345             // Prune the list down to just the requested type.
4346             visibleAccountTypes = new ArrayList<>();
4347             visibleAccountTypes.add(type);
4348         } // else aggregate all the visible accounts (it won't matter if the
4349           // list is empty).
4350 
4351         long identityToken = clearCallingIdentity();
4352         try {
4353             UserAccounts accounts = getUserAccounts(userId);
4354             return getAccountsInternal(
4355                     accounts,
4356                     callingUid,
4357                     opPackageName,
4358                     visibleAccountTypes,
4359                     includeUserManagedNotVisible);
4360         } finally {
4361             restoreCallingIdentity(identityToken);
4362         }
4363     }
4364 
4365     @NonNull
4366     private Account[] getAccountsInternal(
4367             UserAccounts userAccounts,
4368             int callingUid,
4369             String callingPackage,
4370             List<String> visibleAccountTypes,
4371             boolean includeUserManagedNotVisible) {
4372         ArrayList<Account> visibleAccounts = new ArrayList<>();
4373         for (String visibleType : visibleAccountTypes) {
4374             Account[] accountsForType = getAccountsFromCache(
4375                     userAccounts, visibleType, callingUid, callingPackage,
4376                     includeUserManagedNotVisible);
4377             if (accountsForType != null) {
4378                 visibleAccounts.addAll(Arrays.asList(accountsForType));
4379             }
4380         }
4381         Account[] result = new Account[visibleAccounts.size()];
4382         for (int i = 0; i < visibleAccounts.size(); i++) {
4383             result[i] = visibleAccounts.get(i);
4384         }
4385         return result;
4386     }
4387 
4388     @Override
4389     public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4390             String opPackageName) {
4391         checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
4392         Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
4393         for (Account account : accounts) {
4394             addSharedAccountAsUser(account, userId);
4395         }
4396     }
4397 
4398     private boolean addSharedAccountAsUser(Account account, int userId) {
4399         userId = handleIncomingUser(userId);
4400         UserAccounts accounts = getUserAccounts(userId);
4401         accounts.accountsDb.deleteSharedAccount(account);
4402         long accountId = accounts.accountsDb.insertSharedAccount(account);
4403         if (accountId < 0) {
4404             Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
4405                     + ", skipping the DB insert failed");
4406             return false;
4407         }
4408         logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4409                 accounts);
4410         return true;
4411     }
4412 
4413     public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4414         userId = handleIncomingUser(userId);
4415         UserAccounts accounts = getUserAccounts(userId);
4416         long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4417         int r = accounts.accountsDb.renameSharedAccount(account, newName);
4418         if (r > 0) {
4419             int callingUid = getCallingUid();
4420             logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
4421                     sharedTableAccountId, accounts, callingUid);
4422             // Recursively rename the account.
4423             renameAccountInternal(accounts, account, newName);
4424         }
4425         return r > 0;
4426     }
4427 
4428     public boolean removeSharedAccountAsUser(Account account, int userId) {
4429         return removeSharedAccountAsUser(account, userId, getCallingUid());
4430     }
4431 
4432     private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
4433         userId = handleIncomingUser(userId);
4434         UserAccounts accounts = getUserAccounts(userId);
4435         long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4436         boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
4437         if (deleted) {
4438             logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
4439                     sharedTableAccountId, accounts, callingUid);
4440             removeAccountInternal(accounts, account, callingUid);
4441         }
4442         return deleted;
4443     }
4444 
4445     public Account[] getSharedAccountsAsUser(int userId) {
4446         userId = handleIncomingUser(userId);
4447         UserAccounts accounts = getUserAccounts(userId);
4448         synchronized (accounts.dbLock) {
4449             List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4450             Account[] accountArray = new Account[accountList.size()];
4451             accountList.toArray(accountArray);
4452             return accountArray;
4453         }
4454     }
4455 
4456     @Override
4457     @NonNull
4458     public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
4459         int callingUid = Binder.getCallingUid();
4460         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
4461             // Don't do opPackageName check - caller is system.
4462             throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4463                     + callingUid + " with uid=" + uid);
4464         }
4465         return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
4466                 opPackageName, true /* includeUserManagedNotVisible */);
4467     }
4468 
4469     @Override
4470     @NonNull
4471     public Account[] getAccountsByTypeForPackage(String type, String packageName,
4472             String opPackageName) {
4473         int callingUid =  Binder.getCallingUid();
4474         int userId = UserHandle.getCallingUserId();
4475         mAppOpsManager.checkPackage(callingUid, opPackageName);
4476         int packageUid = -1;
4477         try {
4478             packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4479         } catch (NameNotFoundException re) {
4480             Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
4481             return EMPTY_ACCOUNT_ARRAY;
4482         }
4483         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4484                 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4485                 return EMPTY_ACCOUNT_ARRAY;
4486         }
4487         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4488             return getAccountsAsUserForPackage(type, userId,
4489                 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4490         }
4491         return getAccountsAsUserForPackage(type, userId,
4492                 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
4493     }
4494 
4495     private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4496         if (accounts.length < 1) return false;
4497         if (accounts.length > 1) return true;
4498         Account account = accounts[0];
4499         UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4500         int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4501         if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4502         return false;
4503     }
4504 
4505     private void startChooseAccountActivityWithAccounts(
4506         IAccountManagerResponse response, Account[] accounts, String callingPackage) {
4507         Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4508         intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4509         intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4510                 new AccountManagerResponse(response));
4511         intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
4512 
4513         mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4514     }
4515 
4516     private void handleGetAccountsResult(
4517         IAccountManagerResponse response,
4518         Account[] accounts,
4519         String callingPackage) {
4520 
4521         if (needToStartChooseAccountActivity(accounts, callingPackage)) {
4522             startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
4523             return;
4524         }
4525         if (accounts.length == 1) {
4526             Bundle bundle = new Bundle();
4527             bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4528             bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4529             onResult(response, bundle);
4530             return;
4531         }
4532         // No qualified account exists, return an empty Bundle.
4533         onResult(response, new Bundle());
4534     }
4535 
4536     @Override
4537     public void getAccountByTypeAndFeatures(
4538         IAccountManagerResponse response,
4539         String accountType,
4540         String[] features,
4541         String opPackageName) {
4542 
4543         int callingUid = Binder.getCallingUid();
4544         mAppOpsManager.checkPackage(callingUid, opPackageName);
4545         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4546             Log.v(TAG, "getAccount: accountType " + accountType
4547                     + ", response " + response
4548                     + ", features " + Arrays.toString(features)
4549                     + ", caller's uid " + callingUid
4550                     + ", pid " + Binder.getCallingPid());
4551         }
4552         if (response == null) throw new IllegalArgumentException("response is null");
4553         if (accountType == null) throw new IllegalArgumentException("accountType is null");
4554 
4555         int userId = UserHandle.getCallingUserId();
4556 
4557         long identityToken = clearCallingIdentity();
4558         try {
4559             UserAccounts userAccounts = getUserAccounts(userId);
4560             if (ArrayUtils.isEmpty(features)) {
4561                 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4562                     userAccounts, accountType, callingUid, opPackageName,
4563                     true /* include managed not visible */);
4564                 handleGetAccountsResult(
4565                     response, accountsWithManagedNotVisible, opPackageName);
4566                 return;
4567             }
4568 
4569             IAccountManagerResponse retrieveAccountsResponse =
4570                 new IAccountManagerResponse.Stub() {
4571                 @Override
4572                 public void onResult(Bundle value) throws RemoteException {
4573                     Parcelable[] parcelables = value.getParcelableArray(
4574                         AccountManager.KEY_ACCOUNTS);
4575                     Account[] accounts = new Account[parcelables.length];
4576                     for (int i = 0; i < parcelables.length; i++) {
4577                         accounts[i] = (Account) parcelables[i];
4578                     }
4579                     handleGetAccountsResult(
4580                         response, accounts, opPackageName);
4581                 }
4582 
4583                 @Override
4584                 public void onError(int errorCode, String errorMessage)
4585                         throws RemoteException {
4586                     // Will not be called in this case.
4587                 }
4588             };
4589             new GetAccountsByTypeAndFeatureSession(
4590                     userAccounts,
4591                     retrieveAccountsResponse,
4592                     accountType,
4593                     features,
4594                     callingUid,
4595                     opPackageName,
4596                     true /* include managed not visible */).bind();
4597         } finally {
4598             restoreCallingIdentity(identityToken);
4599         }
4600     }
4601 
4602     @Override
4603     public void getAccountsByFeatures(
4604             IAccountManagerResponse response,
4605             String type,
4606             String[] features,
4607             String opPackageName) {
4608         int callingUid = Binder.getCallingUid();
4609         mAppOpsManager.checkPackage(callingUid, opPackageName);
4610         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4611             Log.v(TAG, "getAccounts: accountType " + type
4612                     + ", response " + response
4613                     + ", features " + Arrays.toString(features)
4614                     + ", caller's uid " + callingUid
4615                     + ", pid " + Binder.getCallingPid());
4616         }
4617         if (response == null) throw new IllegalArgumentException("response is null");
4618         if (type == null) throw new IllegalArgumentException("accountType is null");
4619         int userId = UserHandle.getCallingUserId();
4620 
4621         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4622                 opPackageName);
4623         if (!visibleAccountTypes.contains(type)) {
4624             Bundle result = new Bundle();
4625             // Need to return just the accounts that are from matching signatures.
4626             result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
4627             try {
4628                 response.onResult(result);
4629             } catch (RemoteException e) {
4630                 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4631             }
4632             return;
4633         }
4634 
4635         long identityToken = clearCallingIdentity();
4636         try {
4637             UserAccounts userAccounts = getUserAccounts(userId);
4638             if (features == null || features.length == 0) {
4639                 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4640                         opPackageName, false);
4641                 Bundle result = new Bundle();
4642                 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4643                 onResult(response, result);
4644                 return;
4645             }
4646             new GetAccountsByTypeAndFeatureSession(
4647                     userAccounts,
4648                     response,
4649                     type,
4650                     features,
4651                     callingUid,
4652                     opPackageName,
4653                     false /* include managed not visible */).bind();
4654         } finally {
4655             restoreCallingIdentity(identityToken);
4656         }
4657     }
4658 
4659     @Override
4660     public void onAccountAccessed(String token) throws RemoteException {
4661         final int uid = Binder.getCallingUid();
4662         if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4663             return;
4664         }
4665         final int userId = UserHandle.getCallingUserId();
4666         final long identity = Binder.clearCallingIdentity();
4667         try {
4668             for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4669                 if (Objects.equals(account.getAccessId(), token)) {
4670                     // An app just accessed the account. At this point it knows about
4671                     // it and there is not need to hide this account from the app.
4672                     // Do we need to update account visibility here?
4673                     if (!hasAccountAccess(account, null, uid)) {
4674                         updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4675                                 uid, true);
4676                     }
4677                 }
4678             }
4679         } finally {
4680             Binder.restoreCallingIdentity(identity);
4681         }
4682     }
4683 
4684     @Override
4685     public void onShellCommand(FileDescriptor in, FileDescriptor out,
4686             FileDescriptor err, String[] args, ShellCallback callback,
4687             ResultReceiver resultReceiver) {
4688         new AccountManagerServiceShellCommand(this).exec(this, in, out, err, args,
4689                 callback, resultReceiver);
4690     }
4691 
4692     private abstract class Session extends IAccountAuthenticatorResponse.Stub
4693             implements IBinder.DeathRecipient, ServiceConnection {
4694         IAccountManagerResponse mResponse;
4695         final String mAccountType;
4696         final boolean mExpectActivityLaunch;
4697         final long mCreationTime;
4698         final String mAccountName;
4699         // Indicates if we need to add auth details(like last credential time)
4700         final boolean mAuthDetailsRequired;
4701         // If set, we need to update the last authenticated time. This is
4702         // currently
4703         // used on
4704         // successful confirming credentials.
4705         final boolean mUpdateLastAuthenticatedTime;
4706 
4707         public int mNumResults = 0;
4708         private int mNumRequestContinued = 0;
4709         private int mNumErrors = 0;
4710 
4711         IAccountAuthenticator mAuthenticator = null;
4712 
4713         private final boolean mStripAuthTokenFromResult;
4714         protected final UserAccounts mAccounts;
4715 
4716         public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4717                 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4718                 boolean authDetailsRequired) {
4719             this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4720                     accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4721         }
4722 
4723         public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4724                 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4725                 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
4726             super();
4727             //if (response == null) throw new IllegalArgumentException("response is null");
4728             if (accountType == null) throw new IllegalArgumentException("accountType is null");
4729             mAccounts = accounts;
4730             mStripAuthTokenFromResult = stripAuthTokenFromResult;
4731             mResponse = response;
4732             mAccountType = accountType;
4733             mExpectActivityLaunch = expectActivityLaunch;
4734             mCreationTime = SystemClock.elapsedRealtime();
4735             mAccountName = accountName;
4736             mAuthDetailsRequired = authDetailsRequired;
4737             mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
4738 
4739             synchronized (mSessions) {
4740                 mSessions.put(toString(), this);
4741             }
4742             if (response != null) {
4743                 try {
4744                     response.asBinder().linkToDeath(this, 0 /* flags */);
4745                 } catch (RemoteException e) {
4746                     mResponse = null;
4747                     binderDied();
4748                 }
4749             }
4750         }
4751 
4752         IAccountManagerResponse getResponseAndClose() {
4753             if (mResponse == null) {
4754                 // this session has already been closed
4755                 return null;
4756             }
4757             IAccountManagerResponse response = mResponse;
4758             close(); // this clears mResponse so we need to save the response before this call
4759             return response;
4760         }
4761 
4762         /**
4763          * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4764          * security policy.
4765          *
4766          * In particular we want to make sure that the Authenticator doesn't try to trick users
4767          * into launching arbitrary intents on the device via by tricking to click authenticator
4768          * supplied entries in the system Settings app.
4769          */
4770          protected boolean checkKeyIntent(int authUid, Intent intent) {
4771             // Explicitly set an empty ClipData to ensure that we don't offer to
4772             // promote any Uris contained inside for granting purposes
4773             if (intent.getClipData() == null) {
4774                 intent.setClipData(ClipData.newPlainText(null, null));
4775             }
4776             intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4777                     | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4778                     | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4779                     | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
4780             long bid = Binder.clearCallingIdentity();
4781             try {
4782                 PackageManager pm = mContext.getPackageManager();
4783                 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4784                 if (resolveInfo == null) {
4785                     return false;
4786                 }
4787                 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4788                 int targetUid = targetActivityInfo.applicationInfo.uid;
4789                 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
4790                 if (!isExportedSystemActivity(targetActivityInfo)
4791                         && !pmi.hasSignatureCapability(
4792                                 targetUid, authUid,
4793                                 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
4794                     String pkgName = targetActivityInfo.packageName;
4795                     String activityName = targetActivityInfo.name;
4796                     String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4797                             + "does not share a signature with the supplying authenticator (%s).";
4798                     Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
4799                     return false;
4800                 }
4801                 return true;
4802             } finally {
4803                 Binder.restoreCallingIdentity(bid);
4804             }
4805         }
4806 
4807         private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4808             String className = activityInfo.name;
4809             return "android".equals(activityInfo.packageName) &&
4810                     (GrantCredentialsPermissionActivity.class.getName().equals(className)
4811                     || CantAddAccountActivity.class.getName().equals(className));
4812         }
4813 
4814         private void close() {
4815             synchronized (mSessions) {
4816                 if (mSessions.remove(toString()) == null) {
4817                     // the session was already closed, so bail out now
4818                     return;
4819                 }
4820             }
4821             if (mResponse != null) {
4822                 // stop listening for response deaths
4823                 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4824 
4825                 // clear this so that we don't accidentally send any further results
4826                 mResponse = null;
4827             }
4828             cancelTimeout();
4829             unbind();
4830         }
4831 
4832         @Override
4833         public void binderDied() {
4834             mResponse = null;
4835             close();
4836         }
4837 
4838         protected String toDebugString() {
4839             return toDebugString(SystemClock.elapsedRealtime());
4840         }
4841 
4842         protected String toDebugString(long now) {
4843             return "Session: expectLaunch " + mExpectActivityLaunch
4844                     + ", connected " + (mAuthenticator != null)
4845                     + ", stats (" + mNumResults + "/" + mNumRequestContinued
4846                     + "/" + mNumErrors + ")"
4847                     + ", lifetime " + ((now - mCreationTime) / 1000.0);
4848         }
4849 
4850         void bind() {
4851             if (Log.isLoggable(TAG, Log.VERBOSE)) {
4852                 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4853             }
4854             if (!bindToAuthenticator(mAccountType)) {
4855                 Log.d(TAG, "bind attempt failed for " + toDebugString());
4856                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
4857             }
4858         }
4859 
4860         private void unbind() {
4861             if (mAuthenticator != null) {
4862                 mAuthenticator = null;
4863                 mContext.unbindService(this);
4864             }
4865         }
4866 
4867         public void cancelTimeout() {
4868             mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
4869         }
4870 
4871         @Override
4872         public void onServiceConnected(ComponentName name, IBinder service) {
4873             mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
4874             try {
4875                 run();
4876             } catch (RemoteException e) {
4877                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4878                         "remote exception");
4879             }
4880         }
4881 
4882         @Override
4883         public void onServiceDisconnected(ComponentName name) {
4884             mAuthenticator = null;
4885             IAccountManagerResponse response = getResponseAndClose();
4886             if (response != null) {
4887                 try {
4888                     response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4889                             "disconnected");
4890                 } catch (RemoteException e) {
4891                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4892                         Log.v(TAG, "Session.onServiceDisconnected: "
4893                                 + "caught RemoteException while responding", e);
4894                     }
4895                 }
4896             }
4897         }
4898 
4899         public abstract void run() throws RemoteException;
4900 
4901         public void onTimedOut() {
4902             IAccountManagerResponse response = getResponseAndClose();
4903             if (response != null) {
4904                 try {
4905                     response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4906                             "timeout");
4907                 } catch (RemoteException e) {
4908                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4909                         Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4910                                 e);
4911                     }
4912                 }
4913             }
4914         }
4915 
4916         @Override
4917         public void onResult(Bundle result) {
4918             Bundle.setDefusable(result, true);
4919             mNumResults++;
4920             Intent intent = null;
4921             if (result != null) {
4922                 boolean isSuccessfulConfirmCreds = result.getBoolean(
4923                         AccountManager.KEY_BOOLEAN_RESULT, false);
4924                 boolean isSuccessfulUpdateCredsOrAddAccount =
4925                         result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4926                         && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
4927                 // We should only update lastAuthenticated time, if
4928                 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4929                 // or updateRequest was successful
4930                 boolean needUpdate = mUpdateLastAuthenticatedTime
4931                         && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
4932                 if (needUpdate || mAuthDetailsRequired) {
4933                     boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4934                     if (needUpdate && accountPresent) {
4935                         updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4936                     }
4937                     if (mAuthDetailsRequired) {
4938                         long lastAuthenticatedTime = -1;
4939                         if (accountPresent) {
4940                             lastAuthenticatedTime = mAccounts.accountsDb
4941                                     .findAccountLastAuthenticatedTime(
4942                                             new Account(mAccountName, mAccountType));
4943                         }
4944                         result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
4945                                 lastAuthenticatedTime);
4946                     }
4947                 }
4948             }
4949             if (result != null
4950                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
4951                 if (!checkKeyIntent(
4952                         Binder.getCallingUid(),
4953                         intent)) {
4954                     onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
4955                             "invalid intent in bundle returned");
4956                     return;
4957                 }
4958             }
4959             if (result != null
4960                     && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
4961                 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4962                 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
4963                 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4964                     Account account = new Account(accountName, accountType);
4965                     cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4966                             new UserHandle(mAccounts.userId));
4967                 }
4968             }
4969             IAccountManagerResponse response;
4970             if (mExpectActivityLaunch && result != null
4971                     && result.containsKey(AccountManager.KEY_INTENT)) {
4972                 response = mResponse;
4973             } else {
4974                 response = getResponseAndClose();
4975             }
4976             if (response != null) {
4977                 try {
4978                     if (result == null) {
4979                         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4980                             Log.v(TAG, getClass().getSimpleName()
4981                                     + " calling onError() on response " + response);
4982                         }
4983                         response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
4984                                 "null bundle returned");
4985                     } else {
4986                         if (mStripAuthTokenFromResult) {
4987                             result.remove(AccountManager.KEY_AUTHTOKEN);
4988                         }
4989                         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4990                             Log.v(TAG, getClass().getSimpleName()
4991                                     + " calling onResult() on response " + response);
4992                         }
4993                         if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4994                                 (intent == null)) {
4995                             // All AccountManager error codes are greater than 0
4996                             response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4997                                     result.getString(AccountManager.KEY_ERROR_MESSAGE));
4998                         } else {
4999                             response.onResult(result);
5000                         }
5001                     }
5002                 } catch (RemoteException e) {
5003                     // if the caller is dead then there is no one to care about remote exceptions
5004                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
5005                         Log.v(TAG, "failure while notifying response", e);
5006                     }
5007                 }
5008             }
5009         }
5010 
5011         @Override
5012         public void onRequestContinued() {
5013             mNumRequestContinued++;
5014         }
5015 
5016         @Override
5017         public void onError(int errorCode, String errorMessage) {
5018             mNumErrors++;
5019             IAccountManagerResponse response = getResponseAndClose();
5020             if (response != null) {
5021                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5022                     Log.v(TAG, getClass().getSimpleName()
5023                             + " calling onError() on response " + response);
5024                 }
5025                 try {
5026                     response.onError(errorCode, errorMessage);
5027                 } catch (RemoteException e) {
5028                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
5029                         Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
5030                     }
5031                 }
5032             } else {
5033                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5034                     Log.v(TAG, "Session.onError: already closed");
5035                 }
5036             }
5037         }
5038 
5039         /**
5040          * find the component name for the authenticator and initiate a bind
5041          * if no authenticator or the bind fails then return false, otherwise return true
5042          */
5043         private boolean bindToAuthenticator(String authenticatorType) {
5044             final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
5045             authenticatorInfo = mAuthenticatorCache.getServiceInfo(
5046                     AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
5047             if (authenticatorInfo == null) {
5048                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5049                     Log.v(TAG, "there is no authenticator for " + authenticatorType
5050                             + ", bailing out");
5051                 }
5052                 return false;
5053             }
5054 
5055             if (!isLocalUnlockedUser(mAccounts.userId)
5056                     && !authenticatorInfo.componentInfo.directBootAware) {
5057                 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
5058                         + " which isn't encryption aware");
5059                 return false;
5060             }
5061 
5062             Intent intent = new Intent();
5063             intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
5064             intent.setComponent(authenticatorInfo.componentName);
5065             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5066                 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
5067             }
5068             int flags = Context.BIND_AUTO_CREATE;
5069             if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
5070                 flags |= Context.BIND_ALLOW_INSTANT;
5071             }
5072             if (!mContext.bindServiceAsUser(intent, this, flags, UserHandle.of(mAccounts.userId))) {
5073                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5074                     Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
5075                 }
5076                 return false;
5077             }
5078 
5079             return true;
5080         }
5081     }
5082 
5083     class MessageHandler extends Handler {
5084         MessageHandler(Looper looper) {
5085             super(looper);
5086         }
5087 
5088         @Override
5089         public void handleMessage(Message msg) {
5090             switch (msg.what) {
5091                 case MESSAGE_TIMED_OUT:
5092                     Session session = (Session)msg.obj;
5093                     session.onTimedOut();
5094                     break;
5095 
5096                 case MESSAGE_COPY_SHARED_ACCOUNT:
5097                     copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
5098                     break;
5099 
5100                 default:
5101                     throw new IllegalStateException("unhandled message: " + msg.what);
5102             }
5103         }
5104     }
5105 
5106     private void logRecord(UserAccounts accounts, String action, String tableName) {
5107         logRecord(action, tableName, -1, accounts);
5108     }
5109 
5110     private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
5111         logRecord(action, tableName, -1, accounts, uid);
5112     }
5113 
5114     /*
5115      * This function receives an opened writable database.
5116      */
5117     private void logRecord(String action, String tableName, long accountId,
5118             UserAccounts userAccount) {
5119         logRecord(action, tableName, accountId, userAccount, getCallingUid());
5120     }
5121 
5122     /*
5123      * This function receives an opened writable database and writes to it in a separate thread.
5124      */
5125     private void logRecord(String action, String tableName, long accountId,
5126             UserAccounts userAccount, int callingUid) {
5127 
5128         class LogRecordTask implements Runnable {
5129             private final String action;
5130             private final String tableName;
5131             private final long accountId;
5132             private final UserAccounts userAccount;
5133             private final int callingUid;
5134             private final long userDebugDbInsertionPoint;
5135 
5136             LogRecordTask(final String action,
5137                     final String tableName,
5138                     final long accountId,
5139                     final UserAccounts userAccount,
5140                     final int callingUid,
5141                     final long userDebugDbInsertionPoint) {
5142                 this.action = action;
5143                 this.tableName = tableName;
5144                 this.accountId = accountId;
5145                 this.userAccount = userAccount;
5146                 this.callingUid = callingUid;
5147                 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5148             }
5149 
5150             @Override
5151             public void run() {
5152                 synchronized (userAccount.accountsDb.mDebugStatementLock) {
5153                     SQLiteStatement logStatement = userAccount.accountsDb.getStatementForLogging();
5154                     if (logStatement == null) {
5155                         return; // Can't log.
5156                     }
5157                     logStatement.bindLong(1, accountId);
5158                     logStatement.bindString(2, action);
5159                     logStatement.bindString(3, mDateFormat.format(new Date()));
5160                     logStatement.bindLong(4, callingUid);
5161                     logStatement.bindString(5, tableName);
5162                     logStatement.bindLong(6, userDebugDbInsertionPoint);
5163                     try {
5164                         logStatement.execute();
5165                     } catch (IllegalStateException e) {
5166                         // Guard against crash, DB can already be closed
5167                         // since this statement is executed on a handler thread
5168                         Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
5169                                 + " action=" + action + " tableName=" + tableName + " Error: " + e);
5170                     } finally {
5171                         logStatement.clearBindings();
5172                     }
5173                 }
5174             }
5175         }
5176         long insertionPoint = userAccount.accountsDb.reserveDebugDbInsertionPoint();
5177         if (insertionPoint != -1) {
5178             LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5179                     callingUid, insertionPoint);
5180             mHandler.post(logTask);
5181         }
5182     }
5183 
5184     public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
5185         return asBinder();
5186     }
5187 
5188     /**
5189      * Searches array of arguments for the specified string
5190      * @param args array of argument strings
5191      * @param value value to search for
5192      * @return true if the value is contained in the array
5193      */
5194     private static boolean scanArgs(String[] args, String value) {
5195         if (args != null) {
5196             for (String arg : args) {
5197                 if (value.equals(arg)) {
5198                     return true;
5199                 }
5200             }
5201         }
5202         return false;
5203     }
5204 
5205     @Override
5206     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
5207         if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
5208         final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
5209         final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, "  ");
5210 
5211         final List<UserInfo> users = getUserManager().getUsers();
5212         for (UserInfo user : users) {
5213             ipw.println("User " + user + ":");
5214             ipw.increaseIndent();
5215             dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5216             ipw.println();
5217             ipw.decreaseIndent();
5218         }
5219     }
5220 
5221     private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5222             String[] args, boolean isCheckinRequest) {
5223         if (isCheckinRequest) {
5224             // This is a checkin request. *Only* upload the account types and the count of
5225             // each.
5226             synchronized (userAccounts.dbLock) {
5227                 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5228             }
5229         } else {
5230             Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5231                     Process.SYSTEM_UID, null /* packageName */, false);
5232             fout.println("Accounts: " + accounts.length);
5233             for (Account account : accounts) {
5234                 fout.println("  " + account.toString());
5235             }
5236 
5237             // Add debug information.
5238             fout.println();
5239             synchronized (userAccounts.dbLock) {
5240                 userAccounts.accountsDb.dumpDebugTable(fout);
5241             }
5242             fout.println();
5243             synchronized (mSessions) {
5244                 final long now = SystemClock.elapsedRealtime();
5245                 fout.println("Active Sessions: " + mSessions.size());
5246                 for (Session session : mSessions.values()) {
5247                     fout.println("  " + session.toDebugString(now));
5248                 }
5249             }
5250 
5251             fout.println();
5252             mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
5253 
5254             boolean isUserUnlocked;
5255             synchronized (mUsers) {
5256                 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
5257             }
5258             // Following logs are printed only when user is unlocked.
5259             if (!isUserUnlocked) {
5260                 return;
5261             }
5262             fout.println();
5263             synchronized (userAccounts.dbLock) {
5264                 Map<Account, Map<String, Integer>> allVisibilityValues =
5265                         userAccounts.accountsDb.findAllVisibilityValues();
5266                 fout.println("Account visibility:");
5267                 for (Account account : allVisibilityValues.keySet()) {
5268                     fout.println("  " + account.name);
5269                     Map<String, Integer> visibilities = allVisibilityValues.get(account);
5270                     for (Entry<String, Integer> entry : visibilities.entrySet()) {
5271                         fout.println("    " + entry.getKey() + ", " + entry.getValue());
5272                     }
5273                 }
5274             }
5275         }
5276     }
5277 
5278     private void doNotification(UserAccounts accounts, Account account, CharSequence message,
5279             Intent intent, String packageName, final int userId) {
5280         long identityToken = clearCallingIdentity();
5281         try {
5282             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5283                 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5284             }
5285 
5286             if (intent.getComponent() != null &&
5287                     GrantCredentialsPermissionActivity.class.getName().equals(
5288                             intent.getComponent().getClassName())) {
5289                 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
5290             } else {
5291                 Context contextForUser = getContextForUser(new UserHandle(userId));
5292                 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5293                 intent.addCategory(id.mTag);
5294 
5295                 final String notificationTitleFormat =
5296                         contextForUser.getText(R.string.notification_title).toString();
5297                 Notification n =
5298                         new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
5299                         .setWhen(0)
5300                         .setSmallIcon(android.R.drawable.stat_sys_warning)
5301                         .setColor(contextForUser.getColor(
5302                                 com.android.internal.R.color.system_notification_accent_color))
5303                         .setContentTitle(String.format(notificationTitleFormat, account.name))
5304                         .setContentText(message)
5305                         .setContentIntent(PendingIntent.getActivityAsUser(
5306                                 mContext, 0, intent,
5307                                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
5308                                 null, new UserHandle(userId)))
5309                         .build();
5310                 installNotification(id, n, packageName, userId);
5311             }
5312         } finally {
5313             restoreCallingIdentity(identityToken);
5314         }
5315     }
5316 
5317     private void installNotification(NotificationId id, final Notification notification,
5318             String packageName, int userId) {
5319         final long token = clearCallingIdentity();
5320         try {
5321             INotificationManager notificationManager = mInjector.getNotificationManager();
5322             try {
5323                 // The calling uid must match either the package or op package, so use an op
5324                 // package that matches the cleared calling identity.
5325                 notificationManager.enqueueNotificationWithTag(packageName, "android",
5326                         id.mTag, id.mId, notification, userId);
5327             } catch (RemoteException e) {
5328                 /* ignore - local call */
5329             }
5330         } finally {
5331             Binder.restoreCallingIdentity(token);
5332         }
5333     }
5334 
5335     private void cancelNotification(NotificationId id, UserHandle user) {
5336         cancelNotification(id, mContext.getPackageName(), user);
5337     }
5338 
5339     private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
5340         long identityToken = clearCallingIdentity();
5341         try {
5342             INotificationManager service = mInjector.getNotificationManager();
5343             service.cancelNotificationWithTag(
5344                     packageName, "android", id.mTag, id.mId, user.getIdentifier());
5345         } catch (RemoteException e) {
5346             /* ignore - local call */
5347         } finally {
5348             restoreCallingIdentity(identityToken);
5349         }
5350     }
5351 
5352     private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
5353         final long identity = Binder.clearCallingIdentity();
5354         try {
5355             final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5356             IPackageManager pm = ActivityThread.getPackageManager();
5357             for (String perm : permissions) {
5358                 if (pm.checkPermission(perm, packageName, userId)
5359                         == PackageManager.PERMISSION_GRANTED) {
5360                     // Checks runtime permission revocation.
5361                     final int opCode = AppOpsManager.permissionToOpCode(perm);
5362                     if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.checkOpNoThrow(
5363                             opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5364                         return true;
5365                     }
5366                 }
5367             }
5368         } catch (NameNotFoundException | RemoteException e) {
5369             // Assume permission is not granted if an error accrued.
5370         } finally {
5371             Binder.restoreCallingIdentity(identity);
5372         }
5373         return false;
5374     }
5375 
5376     /**
5377      * Checks that package has at least one of given permissions and makes note of app
5378      * performing the action.
5379      */
5380     private boolean checkPermissionAndNote(String opPackageName, int callingUid,
5381             String... permissions) {
5382         for (String perm : permissions) {
5383             if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5384                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5385                     Log.v(TAG, "  caller uid " + callingUid + " has " + perm);
5386                 }
5387                 final int opCode = AppOpsManager.permissionToOpCode(perm);
5388                 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
5389                         opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5390                     return true;
5391                 }
5392             }
5393         }
5394         return false;
5395     }
5396 
5397     private int handleIncomingUser(int userId) {
5398         try {
5399             return ActivityManager.getService().handleIncomingUser(
5400                     Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5401         } catch (RemoteException re) {
5402             // Shouldn't happen, local.
5403         }
5404         return userId;
5405     }
5406 
5407     private boolean isPrivileged(int callingUid) {
5408         String[] packages;
5409         long identityToken = Binder.clearCallingIdentity();
5410         try {
5411             packages = mPackageManager.getPackagesForUid(callingUid);
5412             if (packages == null) {
5413                 Log.d(TAG, "No packages for callingUid " + callingUid);
5414                 return false;
5415             }
5416             for (String name : packages) {
5417                 try {
5418                     PackageInfo packageInfo =
5419                         mPackageManager.getPackageInfo(name, 0 /* flags */);
5420                     if (packageInfo != null
5421                         && (packageInfo.applicationInfo.privateFlags
5422                             & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
5423                         return true;
5424                     }
5425                 } catch (PackageManager.NameNotFoundException e) {
5426                     Log.d(TAG, "Package not found " + e.getMessage());
5427                 }
5428             }
5429         } finally {
5430             Binder.restoreCallingIdentity(identityToken);
5431         }
5432         return false;
5433     }
5434 
5435     private boolean permissionIsGranted(
5436             Account account, String authTokenType, int callerUid, int userId) {
5437         if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5438             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5439                 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5440             }
5441             return true;
5442         }
5443 
5444         if (isPrivileged(callerUid)) {
5445             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5446                 Log.v(TAG, "Access to " + account + " granted calling uid "
5447                         + callerUid + " privileged");
5448             }
5449             return true;
5450         }
5451         if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5452             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5453                 Log.v(TAG, "Access to " + account + " granted calling uid "
5454                         + callerUid + " manages the account");
5455             }
5456             return true;
5457         }
5458         if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5459             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5460                 Log.v(TAG, "Access to " + account + " granted calling uid "
5461                         + callerUid + " user granted access");
5462             }
5463             return true;
5464         }
5465 
5466         if (Log.isLoggable(TAG, Log.VERBOSE)) {
5467             Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5468         }
5469 
5470         return false;
5471     }
5472 
5473     private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5474             String opPackageName) {
5475         if (accountType == null) {
5476             return false;
5477         } else {
5478             return getTypesVisibleToCaller(callingUid, userId,
5479                     opPackageName).contains(accountType);
5480         }
5481     }
5482 
5483     // Method checks visibility for applications targeing API level below {@link
5484     // android.os.Build.VERSION_CODES#O},
5485     // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
5486     private boolean checkGetAccountsPermission(String packageName, int userId) {
5487         return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5488                 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5489     }
5490 
5491     private boolean checkReadContactsPermission(String packageName, int userId) {
5492         return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5493     }
5494 
5495     // Heuristic to check that account type may be associated with some contacts data and
5496     // therefore READ_CONTACTS permission grants the access to account by default.
5497     private boolean accountTypeManagesContacts(String accountType, int userId) {
5498         if (accountType == null) {
5499             return false;
5500         }
5501         long identityToken = Binder.clearCallingIdentity();
5502         Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5503         try {
5504             serviceInfos = mAuthenticatorCache.getAllServices(userId);
5505         } finally {
5506             Binder.restoreCallingIdentity(identityToken);
5507         }
5508         // Check contacts related permissions for authenticator.
5509         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5510                 : serviceInfos) {
5511             if (accountType.equals(serviceInfo.type.type)) {
5512                 return isPermittedForPackage(serviceInfo.type.packageName, userId,
5513                     Manifest.permission.WRITE_CONTACTS);
5514             }
5515         }
5516         return false;
5517     }
5518 
5519     /**
5520      * Method checks package uid and signature with Authenticator which manages accountType.
5521      *
5522      * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5523      *         SIGNATURE_CHECK_MISMATCH otherwise.
5524      */
5525     private int checkPackageSignature(String accountType, int callingUid, int userId) {
5526         if (accountType == null) {
5527             return SIGNATURE_CHECK_MISMATCH;
5528         }
5529 
5530         long identityToken = Binder.clearCallingIdentity();
5531         Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5532         try {
5533             serviceInfos = mAuthenticatorCache.getAllServices(userId);
5534         } finally {
5535             Binder.restoreCallingIdentity(identityToken);
5536         }
5537         // Check for signature match with Authenticator.LocalServices.getService(PackageManagerInternal.class);
5538         PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
5539         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5540                 : serviceInfos) {
5541             if (accountType.equals(serviceInfo.type.type)) {
5542                 if (serviceInfo.uid == callingUid) {
5543                     return SIGNATURE_CHECK_UID_MATCH;
5544                 }
5545                 if (pmi.hasSignatureCapability(
5546                         serviceInfo.uid, callingUid,
5547                         PackageParser.SigningDetails.CertCapabilities.AUTH)) {
5548                     return SIGNATURE_CHECK_MATCH;
5549                 }
5550             }
5551         }
5552         return SIGNATURE_CHECK_MISMATCH;
5553     }
5554 
5555     // returns true for applications with the same signature as authenticator.
5556     private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5557         if (accountType == null) {
5558             return false;
5559         } else {
5560             return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5561         }
5562     }
5563 
5564     private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5565             String opPackageName) {
5566         return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
5567     }
5568 
5569     private List<String> getTypesManagedByCaller(int callingUid, int userId) {
5570         return getTypesForCaller(callingUid, userId, false);
5571     }
5572 
5573     private List<String> getTypesForCaller(
5574             int callingUid, int userId, boolean isOtherwisePermitted) {
5575         List<String> managedAccountTypes = new ArrayList<>();
5576         long identityToken = Binder.clearCallingIdentity();
5577         Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5578         try {
5579             serviceInfos = mAuthenticatorCache.getAllServices(userId);
5580         } finally {
5581             Binder.restoreCallingIdentity(identityToken);
5582         }
5583 
5584         PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
5585         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
5586                 serviceInfos) {
5587             if (isOtherwisePermitted || pmi.hasSignatureCapability(
5588                     serviceInfo.uid, callingUid,
5589                     PackageParser.SigningDetails.CertCapabilities.AUTH)) {
5590                 managedAccountTypes.add(serviceInfo.type.type);
5591             }
5592         }
5593         return managedAccountTypes;
5594     }
5595 
5596     private boolean isAccountPresentForCaller(String accountName, String accountType) {
5597         if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5598             for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5599                 if (account.name.equals(accountName)) {
5600                     return true;
5601                 }
5602             }
5603         }
5604         return false;
5605     }
5606 
5607     private static void checkManageUsersPermission(String message) {
5608         if (ActivityManager.checkComponentPermission(
5609                 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5610                 != PackageManager.PERMISSION_GRANTED) {
5611             throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5612         }
5613     }
5614 
5615     private static void checkManageOrCreateUsersPermission(String message) {
5616         if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5617                 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5618                 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5619                         Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5620             throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5621                     + message);
5622         }
5623     }
5624 
5625     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5626             int callerUid) {
5627         if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5628             return true;
5629         }
5630         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
5631         synchronized (accounts.dbLock) {
5632             synchronized (accounts.cacheLock) {
5633                 long grantsCount;
5634                 if (authTokenType != null) {
5635                     grantsCount = accounts.accountsDb
5636                             .findMatchingGrantsCount(callerUid, authTokenType, account);
5637                 } else {
5638                     grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5639                             account);
5640                 }
5641                 final boolean permissionGranted = grantsCount > 0;
5642 
5643                 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5644                     // TODO: Skip this check when running automated tests. Replace this
5645                     // with a more general solution.
5646                     Log.d(TAG, "no credentials permission for usage of "
5647                             + account.toSafeString() + ", "
5648                             + authTokenType + " by uid " + callerUid
5649                             + " but ignoring since device is in test harness.");
5650                     return true;
5651                 }
5652                 return permissionGranted;
5653             }
5654         }
5655     }
5656 
5657     private boolean isSystemUid(int callingUid) {
5658         String[] packages = null;
5659         long ident = Binder.clearCallingIdentity();
5660         try {
5661             packages = mPackageManager.getPackagesForUid(callingUid);
5662             if (packages != null) {
5663                 for (String name : packages) {
5664                     try {
5665                         PackageInfo packageInfo =
5666                                 mPackageManager.getPackageInfo(name, 0 /* flags */);
5667                         if (packageInfo != null
5668                                 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5669                                 != 0) {
5670                             return true;
5671                         }
5672                     } catch (NameNotFoundException e) {
5673                         Log.w(TAG, String.format("Could not find package [%s]", name), e);
5674                     }
5675                 }
5676             } else {
5677                 Log.w(TAG, "No known packages with uid " + callingUid);
5678             }
5679         } finally {
5680             Binder.restoreCallingIdentity(ident);
5681         }
5682         return false;
5683     }
5684 
5685     /** Succeeds if any of the specified permissions are granted. */
5686     private void checkReadAccountsPermitted(
5687             int callingUid,
5688             String accountType,
5689             int userId,
5690             String opPackageName) {
5691         if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
5692             String msg = String.format(
5693                     "caller uid %s cannot access %s accounts",
5694                     callingUid,
5695                     accountType);
5696             Log.w(TAG, "  " + msg);
5697             throw new SecurityException(msg);
5698         }
5699     }
5700 
5701     private boolean canUserModifyAccounts(int userId, int callingUid) {
5702         // the managing app can always modify accounts
5703         if (isProfileOwner(callingUid)) {
5704             return true;
5705         }
5706         if (getUserManager().getUserRestrictions(new UserHandle(userId))
5707                 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5708             return false;
5709         }
5710         return true;
5711     }
5712 
5713     private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5714         // the managing app can always modify accounts
5715         if (isProfileOwner(callingUid)) {
5716             return true;
5717         }
5718         DevicePolicyManager dpm = (DevicePolicyManager) mContext
5719                 .getSystemService(Context.DEVICE_POLICY_SERVICE);
5720         String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
5721         if (typesArray == null) {
5722             return true;
5723         }
5724         for (String forbiddenType : typesArray) {
5725             if (forbiddenType.equals(accountType)) {
5726                 return false;
5727             }
5728         }
5729         return true;
5730     }
5731 
5732     private boolean isProfileOwner(int uid) {
5733         final DevicePolicyManagerInternal dpmi =
5734                 LocalServices.getService(DevicePolicyManagerInternal.class);
5735         return (dpmi != null)
5736                 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5737     }
5738 
5739     @Override
5740     public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5741             throws RemoteException {
5742         final int callingUid = getCallingUid();
5743 
5744         if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
5745             throw new SecurityException();
5746         }
5747 
5748         if (value) {
5749             grantAppPermission(account, authTokenType, uid);
5750         } else {
5751             revokeAppPermission(account, authTokenType, uid);
5752         }
5753     }
5754 
5755     /**
5756      * Allow callers with the given uid permission to get credentials for account/authTokenType.
5757      * <p>
5758      * Although this is public it can only be accessed via the AccountManagerService object
5759      * which is in the system. This means we don't need to protect it with permissions.
5760      * @hide
5761      */
5762     void grantAppPermission(Account account, String authTokenType, int uid) {
5763         if (account == null || authTokenType == null) {
5764             Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
5765             return;
5766         }
5767         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
5768         synchronized (accounts.dbLock) {
5769             synchronized (accounts.cacheLock) {
5770                 long accountId = accounts.accountsDb.findDeAccountId(account);
5771                 if (accountId >= 0) {
5772                     accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5773                 }
5774                 cancelNotification(
5775                         getCredentialPermissionNotificationId(account, authTokenType, uid),
5776                         UserHandle.of(accounts.userId));
5777 
5778                 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5779             }
5780         }
5781 
5782         // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5783         for (AccountManagerInternal.OnAppPermissionChangeListener listener
5784                 : mAppPermissionChangeListeners) {
5785             mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5786         }
5787     }
5788 
5789     /**
5790      * Don't allow callers with the given uid permission to get credentials for
5791      * account/authTokenType.
5792      * <p>
5793      * Although this is public it can only be accessed via the AccountManagerService object
5794      * which is in the system. This means we don't need to protect it with permissions.
5795      * @hide
5796      */
5797     private void revokeAppPermission(Account account, String authTokenType, int uid) {
5798         if (account == null || authTokenType == null) {
5799             Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
5800             return;
5801         }
5802         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
5803         synchronized (accounts.dbLock) {
5804             synchronized (accounts.cacheLock) {
5805                 accounts.accountsDb.beginTransaction();
5806                 try {
5807                     long accountId = accounts.accountsDb.findDeAccountId(account);
5808                     if (accountId >= 0) {
5809                         accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5810                                 accountId, authTokenType, uid);
5811                         accounts.accountsDb.setTransactionSuccessful();
5812                     }
5813                 } finally {
5814                     accounts.accountsDb.endTransaction();
5815                 }
5816 
5817                 cancelNotification(
5818                         getCredentialPermissionNotificationId(account, authTokenType, uid),
5819                         UserHandle.of(accounts.userId));
5820             }
5821         }
5822 
5823         // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5824         for (AccountManagerInternal.OnAppPermissionChangeListener listener
5825                 : mAppPermissionChangeListeners) {
5826             mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5827         }
5828     }
5829 
5830     private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5831         final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
5832         if (oldAccountsForType != null) {
5833             ArrayList<Account> newAccountsList = new ArrayList<>();
5834             for (Account curAccount : oldAccountsForType) {
5835                 if (!curAccount.equals(account)) {
5836                     newAccountsList.add(curAccount);
5837                 }
5838             }
5839             if (newAccountsList.isEmpty()) {
5840                 accounts.accountCache.remove(account.type);
5841             } else {
5842                 Account[] newAccountsForType = new Account[newAccountsList.size()];
5843                 newAccountsForType = newAccountsList.toArray(newAccountsForType);
5844                 accounts.accountCache.put(account.type, newAccountsForType);
5845             }
5846         }
5847         accounts.userDataCache.remove(account);
5848         accounts.authTokenCache.remove(account);
5849         accounts.previousNameCache.remove(account);
5850         accounts.visibilityCache.remove(account);
5851     }
5852 
5853     /**
5854      * This assumes that the caller has already checked that the account is not already present.
5855      * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5856      * processes and if you will return this account to apps you should return the result.
5857      * @return The inserted account which is a new instance that is being tracked.
5858      */
5859     private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
5860         Account[] accountsForType = accounts.accountCache.get(account.type);
5861         int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5862         Account[] newAccountsForType = new Account[oldLength + 1];
5863         if (accountsForType != null) {
5864             System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
5865         }
5866         String token = account.getAccessId() != null ? account.getAccessId()
5867                 : UUID.randomUUID().toString();
5868         newAccountsForType[oldLength] = new Account(account, token);
5869         accounts.accountCache.put(account.type, newAccountsForType);
5870         return newAccountsForType[oldLength];
5871     }
5872 
5873     @NonNull
5874     private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
5875             @Nullable String callingPackage, boolean includeManagedNotVisible) {
5876         String visibilityFilterPackage = callingPackage;
5877         if (visibilityFilterPackage == null) {
5878             visibilityFilterPackage = getPackageNameForUid(callingUid);
5879         }
5880         Map<Account, Integer> firstPass = new LinkedHashMap<>();
5881         for (Account account : unfiltered) {
5882             int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
5883             if ((visibility == AccountManager.VISIBILITY_VISIBLE
5884                     || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5885                     || (includeManagedNotVisible
5886                             && (visibility
5887                                     == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5888                 firstPass.put(account, visibility);
5889             }
5890         }
5891         Map<Account, Integer> secondPass =
5892                 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5893 
5894         Account[] filtered = new Account[secondPass.size()];
5895         filtered = secondPass.keySet().toArray(filtered);
5896         return filtered;
5897     }
5898 
5899     @NonNull
5900     private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
5901             @NonNull Map<Account, Integer> unfiltered, int callingUid,
5902             @Nullable String callingPackage) {
5903         // first part is to filter shared accounts.
5904         // unfiltered type check is not necessary.
5905         if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
5906                 || callingUid == Process.SYSTEM_UID) {
5907             return unfiltered;
5908         }
5909         UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
5910         if (user != null && user.isRestricted()) {
5911             String[] packages = mPackageManager.getPackagesForUid(callingUid);
5912             if (packages == null) {
5913                 packages = new String[] {};
5914             }
5915             // If any of the packages is a visible listed package, return the full set,
5916             // otherwise return non-shared accounts only.
5917             // This might be a temporary way to specify a visible list
5918             String visibleList = mContext.getResources().getString(
5919                     com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5920             for (String packageName : packages) {
5921                 if (visibleList.contains(";" + packageName + ";")) {
5922                     return unfiltered;
5923                 }
5924             }
5925             Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
5926             if (ArrayUtils.isEmpty(sharedAccounts)) {
5927                 return unfiltered;
5928             }
5929             String requiredAccountType = "";
5930             try {
5931                 // If there's an explicit callingPackage specified, check if that package
5932                 // opted in to see restricted accounts.
5933                 if (callingPackage != null) {
5934                     PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
5935                     if (pi != null && pi.restrictedAccountType != null) {
5936                         requiredAccountType = pi.restrictedAccountType;
5937                     }
5938                 } else {
5939                     // Otherwise check if the callingUid has a package that has opted in
5940                     for (String packageName : packages) {
5941                         PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5942                         if (pi != null && pi.restrictedAccountType != null) {
5943                             requiredAccountType = pi.restrictedAccountType;
5944                             break;
5945                         }
5946                     }
5947                 }
5948             } catch (NameNotFoundException e) {
5949                 Log.d(TAG, "Package not found " + e.getMessage());
5950             }
5951             Map<Account, Integer> filtered = new LinkedHashMap<>();
5952             for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5953                 Account account = entry.getKey();
5954                 if (account.type.equals(requiredAccountType)) {
5955                     filtered.put(account, entry.getValue());
5956                 } else {
5957                     boolean found = false;
5958                     for (Account shared : sharedAccounts) {
5959                         if (shared.equals(account)) {
5960                             found = true;
5961                             break;
5962                         }
5963                     }
5964                     if (!found) {
5965                         filtered.put(account, entry.getValue());
5966                     }
5967                 }
5968             }
5969             return filtered;
5970         } else {
5971             return unfiltered;
5972         }
5973     }
5974 
5975     /*
5976      * packageName can be null. If not null, it should be used to filter out restricted accounts
5977      * that the package is not allowed to access.
5978      *
5979      * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5980      * deadlock
5981      */
5982     @NonNull
5983     protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
5984             int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
5985         Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5986                 "Method should not be called with cacheLock");
5987         if (accountType != null) {
5988             Account[] accounts;
5989             synchronized (userAccounts.cacheLock) {
5990                 accounts = userAccounts.accountCache.get(accountType);
5991             }
5992             if (accounts == null) {
5993                 return EMPTY_ACCOUNT_ARRAY;
5994             } else {
5995                 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5996                         callingUid, callingPackage, includeManagedNotVisible);
5997             }
5998         } else {
5999             int totalLength = 0;
6000             Account[] accountsArray;
6001             synchronized (userAccounts.cacheLock) {
6002                 for (Account[] accounts : userAccounts.accountCache.values()) {
6003                     totalLength += accounts.length;
6004                 }
6005                 if (totalLength == 0) {
6006                     return EMPTY_ACCOUNT_ARRAY;
6007                 }
6008                 accountsArray = new Account[totalLength];
6009                 totalLength = 0;
6010                 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
6011                     System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
6012                             accountsOfType.length);
6013                     totalLength += accountsOfType.length;
6014                 }
6015             }
6016             return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
6017                     includeManagedNotVisible);
6018         }
6019     }
6020 
6021     /** protected by the {@code dbLock}, {@code cacheLock} */
6022     protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
6023             Account account, String key, String value) {
6024         Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
6025         if (userDataForAccount == null) {
6026             userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6027             accounts.userDataCache.put(account, userDataForAccount);
6028         }
6029         if (value == null) {
6030             userDataForAccount.remove(key);
6031         } else {
6032             userDataForAccount.put(key, value);
6033         }
6034     }
6035 
6036     protected String readCachedTokenInternal(
6037             UserAccounts accounts,
6038             Account account,
6039             String tokenType,
6040             String callingPackage,
6041             byte[] pkgSigDigest) {
6042         synchronized (accounts.cacheLock) {
6043             return accounts.accountTokenCaches.get(
6044                     account, tokenType, callingPackage, pkgSigDigest);
6045         }
6046     }
6047 
6048     /** protected by the {@code dbLock}, {@code cacheLock} */
6049     protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
6050             Account account, String key, String value) {
6051         Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6052         if (authTokensForAccount == null) {
6053             authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6054             accounts.authTokenCache.put(account, authTokensForAccount);
6055         }
6056         if (value == null) {
6057             authTokensForAccount.remove(key);
6058         } else {
6059             authTokensForAccount.put(key, value);
6060         }
6061     }
6062 
6063     protected String readAuthTokenInternal(UserAccounts accounts, Account account,
6064             String authTokenType) {
6065         // Fast path - check if account is already cached
6066         synchronized (accounts.cacheLock) {
6067             Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6068             if (authTokensForAccount != null) {
6069                 return authTokensForAccount.get(authTokenType);
6070             }
6071         }
6072         // If not cached yet - do slow path and sync with db if necessary
6073         synchronized (accounts.dbLock) {
6074             synchronized (accounts.cacheLock) {
6075                 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6076                 if (authTokensForAccount == null) {
6077                     // need to populate the cache for this account
6078                     authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6079                     accounts.authTokenCache.put(account, authTokensForAccount);
6080                 }
6081                 return authTokensForAccount.get(authTokenType);
6082             }
6083         }
6084     }
6085 
6086     private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
6087         Map<String, String> userDataForAccount;
6088         // Fast path - check if data is already cached
6089         synchronized (accounts.cacheLock) {
6090             userDataForAccount = accounts.userDataCache.get(account);
6091         }
6092         // If not cached yet - do slow path and sync with db if necessary
6093         if (userDataForAccount == null) {
6094             synchronized (accounts.dbLock) {
6095                 synchronized (accounts.cacheLock) {
6096                     userDataForAccount = accounts.userDataCache.get(account);
6097                     if (userDataForAccount == null) {
6098                         // need to populate the cache for this account
6099                         userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6100                         accounts.userDataCache.put(account, userDataForAccount);
6101                     }
6102                 }
6103             }
6104         }
6105         return userDataForAccount.get(key);
6106     }
6107 
6108     private Context getContextForUser(UserHandle user) {
6109         try {
6110             return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
6111         } catch (NameNotFoundException e) {
6112             // Default to mContext, not finding the package system is running as is unlikely.
6113             return mContext;
6114         }
6115     }
6116 
6117     private void sendResponse(IAccountManagerResponse response, Bundle result) {
6118         try {
6119             response.onResult(result);
6120         } catch (RemoteException e) {
6121             // if the caller is dead then there is no one to care about remote
6122             // exceptions
6123             if (Log.isLoggable(TAG, Log.VERBOSE)) {
6124                 Log.v(TAG, "failure while notifying response", e);
6125             }
6126         }
6127     }
6128 
6129     private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6130             String errorMessage) {
6131         try {
6132             response.onError(errorCode, errorMessage);
6133         } catch (RemoteException e) {
6134             // if the caller is dead then there is no one to care about remote
6135             // exceptions
6136             if (Log.isLoggable(TAG, Log.VERBOSE)) {
6137                 Log.v(TAG, "failure while notifying response", e);
6138             }
6139         }
6140     }
6141 
6142     private final class AccountManagerInternalImpl extends AccountManagerInternal {
6143         private final Object mLock = new Object();
6144 
6145         @GuardedBy("mLock")
6146         private AccountManagerBackupHelper mBackupHelper;
6147 
6148         @Override
6149         public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6150                 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6151             if (account == null) {
6152                 Slog.w(TAG, "account cannot be null");
6153                 return;
6154             }
6155             if (packageName == null) {
6156                 Slog.w(TAG, "packageName cannot be null");
6157                 return;
6158             }
6159             if (userId < UserHandle.USER_SYSTEM) {
6160                 Slog.w(TAG, "user id must be concrete");
6161                 return;
6162             }
6163             if (callback == null) {
6164                 Slog.w(TAG, "callback cannot be null");
6165                 return;
6166             }
6167 
6168             int visibility =
6169                 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6170             if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6171                 Slog.w(TAG, "requestAccountAccess: account is hidden");
6172                 return;
6173             }
6174 
6175             if (AccountManagerService.this.hasAccountAccess(account, packageName,
6176                     new UserHandle(userId))) {
6177                 Bundle result = new Bundle();
6178                 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6179                 callback.sendResult(result);
6180                 return;
6181             }
6182 
6183             final int uid;
6184             try {
6185                 long identityToken = clearCallingIdentity();
6186                 try {
6187                     uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6188                 } finally {
6189                     restoreCallingIdentity(identityToken);
6190                 }
6191             } catch (NameNotFoundException e) {
6192                 Slog.e(TAG, "Unknown package " + packageName);
6193                 return;
6194             }
6195 
6196             Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
6197             final UserAccounts userAccounts;
6198             synchronized (mUsers) {
6199                 userAccounts = mUsers.get(userId);
6200             }
6201             SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
6202             doNotification(userAccounts, account, null, intent, packageName, userId);
6203         }
6204 
6205         @Override
6206         public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6207             // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6208             mAppPermissionChangeListeners.add(listener);
6209         }
6210 
6211         @Override
6212         public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6213             return AccountManagerService.this.hasAccountAccess(account, null, uid);
6214         }
6215 
6216         @Override
6217         public byte[] backupAccountAccessPermissions(int userId) {
6218             synchronized (mLock) {
6219                 if (mBackupHelper == null) {
6220                     mBackupHelper = new AccountManagerBackupHelper(
6221                             AccountManagerService.this, this);
6222                 }
6223                 return mBackupHelper.backupAccountAccessPermissions(userId);
6224             }
6225         }
6226 
6227         @Override
6228         public void restoreAccountAccessPermissions(byte[] data, int userId) {
6229             synchronized (mLock) {
6230                 if (mBackupHelper == null) {
6231                     mBackupHelper = new AccountManagerBackupHelper(
6232                             AccountManagerService.this, this);
6233                 }
6234                 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6235             }
6236         }
6237     }
6238 
6239     @VisibleForTesting
6240     static class Injector {
6241         private final Context mContext;
6242 
6243         public Injector(Context context) {
6244             mContext = context;
6245         }
6246 
6247         Looper getMessageHandlerLooper() {
6248             ServiceThread serviceThread = new ServiceThread(TAG,
6249                     android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6250             serviceThread.start();
6251             return serviceThread.getLooper();
6252         }
6253 
6254         Context getContext() {
6255             return mContext;
6256         }
6257 
6258         void addLocalService(AccountManagerInternal service) {
6259             LocalServices.addService(AccountManagerInternal.class, service);
6260         }
6261 
6262         String getDeDatabaseName(int userId) {
6263             File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6264                     AccountsDb.DE_DATABASE_NAME);
6265             return databaseFile.getPath();
6266         }
6267 
6268         String getCeDatabaseName(int userId) {
6269             File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6270                     AccountsDb.CE_DATABASE_NAME);
6271             return databaseFile.getPath();
6272         }
6273 
6274         String getPreNDatabaseName(int userId) {
6275             File systemDir = Environment.getDataSystemDirectory();
6276             File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6277                     PRE_N_DATABASE_NAME);
6278             if (userId == 0) {
6279                 // Migrate old file, if it exists, to the new location.
6280                 // Make sure the new file doesn't already exist. A dummy file could have been
6281                 // accidentally created in the old location,
6282                 // causing the new one to become corrupted as well.
6283                 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6284                 if (oldFile.exists() && !databaseFile.exists()) {
6285                     // Check for use directory; create if it doesn't exist, else renameTo will fail
6286                     File userDir = Environment.getUserSystemDirectory(userId);
6287                     if (!userDir.exists()) {
6288                         if (!userDir.mkdirs()) {
6289                             throw new IllegalStateException(
6290                                     "User dir cannot be created: " + userDir);
6291                         }
6292                     }
6293                     if (!oldFile.renameTo(databaseFile)) {
6294                         throw new IllegalStateException(
6295                                 "User dir cannot be migrated: " + databaseFile);
6296                     }
6297                 }
6298             }
6299             return databaseFile.getPath();
6300         }
6301 
6302         IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6303             return new AccountAuthenticatorCache(mContext);
6304         }
6305 
6306         INotificationManager getNotificationManager() {
6307             return NotificationManager.getService();
6308         }
6309     }
6310 
6311     private static class NotificationId {
6312         final String mTag;
6313         private final int mId;
6314 
6315         NotificationId(String tag, int type) {
6316             mTag = tag;
6317             mId = type;
6318         }
6319     }
6320 }
6321