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