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