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