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                     if (accounts.accountsDb.findAllDeAccounts().size() > 100) {
1837                         Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
1838                                 + ", skipping since more than 50 accounts on device exist");
1839                         return false;
1840                     }
1841                     long accountId = accounts.accountsDb.insertCeAccount(account, password);
1842                     if (accountId < 0) {
1843                         Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
1844                                 + ", skipping the DB insert failed");
1845                         return false;
1846                     }
1847                     // Insert into DE table
1848                     if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1849                         Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
1850                                 + ", skipping the DB insert failed");
1851                         return false;
1852                     }
1853                     if (extras != null) {
1854                         for (String key : extras.keySet()) {
1855                             final String value = extras.getString(key);
1856                             if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1857                                 Log.w(TAG, "insertAccountIntoDatabase: "
1858                                         + account.toSafeString()
1859                                         + ", skipping since insertExtra failed for key " + key);
1860                                 return false;
1861                             } else {
1862                                 AccountManager.invalidateLocalAccountUserDataCaches();
1863                             }
1864                         }
1865                     }
1866 
1867                     if (packageToVisibility != null) {
1868                         for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1869                             setAccountVisibility(account, entry.getKey() /* package */,
1870                                     entry.getValue() /* visibility */, false /* notify */,
1871                                     accounts);
1872                         }
1873                     }
1874                     accounts.accountsDb.setTransactionSuccessful();
1875 
1876                     logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1877                             accountId,
1878                             accounts, callingUid);
1879 
1880                     insertAccountIntoCacheLocked(accounts, account);
1881                 } finally {
1882                     accounts.accountsDb.endTransaction();
1883                 }
1884             }
1885         }
1886         if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1887             addAccountToLinkedRestrictedUsers(account, accounts.userId);
1888         }
1889 
1890         sendNotificationAccountUpdated(account, accounts);
1891         // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1892         sendAccountsChangedBroadcast(accounts.userId);
1893 
1894         logAddAccountExplicitlyMetrics(opPackageName, account.type, packageToVisibility);
1895         return true;
1896     }
1897 
logAddAccountExplicitlyMetrics( String callerPackage, String accountType, @Nullable Map<String, Integer> accountVisibility)1898     private void logAddAccountExplicitlyMetrics(
1899             String callerPackage, String accountType,
1900             @Nullable Map<String, Integer> accountVisibility) {
1901         // Although this is not a 'device policy' API, enterprise is the current use case.
1902         DevicePolicyEventLogger
1903                 .createEvent(DevicePolicyEnums.ADD_ACCOUNT_EXPLICITLY)
1904                 .setStrings(
1905                         TextUtils.emptyIfNull(accountType),
1906                         TextUtils.emptyIfNull(callerPackage),
1907                         findPackagesPerVisibility(accountVisibility))
1908                 .write();
1909     }
1910 
findPackagesPerVisibility(@ullable Map<String, Integer> accountVisibility)1911     private String[] findPackagesPerVisibility(@Nullable Map<String, Integer> accountVisibility) {
1912         Map<Integer, Set<String>> packagesPerVisibility = new HashMap<>();
1913         if (accountVisibility != null) {
1914             for (Entry<String, Integer> entry : accountVisibility.entrySet()) {
1915                 if (!packagesPerVisibility.containsKey(entry.getValue())) {
1916                     packagesPerVisibility.put(entry.getValue(), new HashSet<>());
1917                 }
1918                 packagesPerVisibility.get(entry.getValue()).add(entry.getKey());
1919             }
1920         }
1921 
1922         String[] packagesPerVisibilityStr = new String[5];
1923         packagesPerVisibilityStr[AccountManager.VISIBILITY_UNDEFINED] = getPackagesForVisibilityStr(
1924                 AccountManager.VISIBILITY_UNDEFINED, packagesPerVisibility);
1925         packagesPerVisibilityStr[AccountManager.VISIBILITY_VISIBLE] = getPackagesForVisibilityStr(
1926                 AccountManager.VISIBILITY_VISIBLE, packagesPerVisibility);
1927         packagesPerVisibilityStr[AccountManager.VISIBILITY_USER_MANAGED_VISIBLE] =
1928                 getPackagesForVisibilityStr(
1929                         AccountManager.VISIBILITY_USER_MANAGED_VISIBLE, packagesPerVisibility);
1930         packagesPerVisibilityStr[AccountManager.VISIBILITY_NOT_VISIBLE] =
1931                 getPackagesForVisibilityStr(
1932                         AccountManager.VISIBILITY_NOT_VISIBLE, packagesPerVisibility);
1933         packagesPerVisibilityStr[AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE] =
1934                 getPackagesForVisibilityStr(
1935                         AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE, packagesPerVisibility);
1936         return packagesPerVisibilityStr;
1937     }
1938 
getPackagesForVisibilityStr( int visibility, Map<Integer, Set<String>> packagesPerVisibility)1939     private String getPackagesForVisibilityStr(
1940             int visibility, Map<Integer, Set<String>> packagesPerVisibility) {
1941         return visibility + ":"
1942                 + (packagesPerVisibility.containsKey(visibility)
1943                     ? TextUtils.join(",", packagesPerVisibility.get(visibility))
1944                     : "");
1945     }
1946 
isLocalUnlockedUser(int userId)1947     private boolean isLocalUnlockedUser(int userId) {
1948         synchronized (mUsers) {
1949             return mLocalUnlockedUsers.get(userId);
1950         }
1951     }
1952 
1953     /**
1954      * Adds the account to all linked restricted users as shared accounts. If the user is currently
1955      * running, then clone the account too.
1956      * @param account the account to share with limited users
1957      *
1958      */
addAccountToLinkedRestrictedUsers(Account account, int parentUserId)1959     private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
1960         List<UserInfo> users = getUserManager().getUsers();
1961         for (UserInfo user : users) {
1962             if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
1963                 addSharedAccountAsUser(account, user.id);
1964                 if (isLocalUnlockedUser(user.id)) {
1965                     mHandler.sendMessage(mHandler.obtainMessage(
1966                             MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
1967                 }
1968             }
1969         }
1970     }
1971 
1972     @Override
hasFeatures(IAccountManagerResponse response, Account account, String[] features, String opPackageName)1973     public void hasFeatures(IAccountManagerResponse response,
1974             Account account, String[] features, String opPackageName) {
1975         int callingUid = Binder.getCallingUid();
1976         mAppOpsManager.checkPackage(callingUid, opPackageName);
1977         if (Log.isLoggable(TAG, Log.VERBOSE)) {
1978             Log.v(TAG, "hasFeatures: " + account
1979                     + ", response " + response
1980                     + ", features " + Arrays.toString(features)
1981                     + ", caller's uid " + callingUid
1982                     + ", pid " + Binder.getCallingPid());
1983         }
1984         Preconditions.checkArgument(account != null, "account cannot be null");
1985         Preconditions.checkArgument(response != null, "response cannot be null");
1986         Preconditions.checkArgument(features != null, "features cannot be null");
1987         int userId = UserHandle.getCallingUserId();
1988         checkReadAccountsPermitted(callingUid, account.type, userId,
1989                 opPackageName);
1990 
1991         final long identityToken = clearCallingIdentity();
1992         try {
1993             UserAccounts accounts = getUserAccounts(userId);
1994             new TestFeaturesSession(accounts, response, account, features).bind();
1995         } finally {
1996             restoreCallingIdentity(identityToken);
1997         }
1998     }
1999 
2000     private class TestFeaturesSession extends Session {
2001         private final String[] mFeatures;
2002         private final Account mAccount;
2003 
TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response, Account account, String[] features)2004         public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
2005                 Account account, String[] features) {
2006             super(accounts, response, account.type, false /* expectActivityLaunch */,
2007                     true /* stripAuthTokenFromResult */, account.name,
2008                     false /* authDetailsRequired */);
2009             mFeatures = features;
2010             mAccount = account;
2011         }
2012 
2013         @Override
run()2014         public void run() throws RemoteException {
2015             try {
2016                 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
2017             } catch (RemoteException e) {
2018                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
2019             }
2020         }
2021 
2022         @Override
onResult(Bundle result)2023         public void onResult(Bundle result) {
2024             Bundle.setDefusable(result, true);
2025             IAccountManagerResponse response = getResponseAndClose();
2026             if (response != null) {
2027                 try {
2028                     if (result == null) {
2029                         response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
2030                         return;
2031                     }
2032                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
2033                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2034                                 + response);
2035                     }
2036                     final Bundle newResult = new Bundle();
2037                     newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
2038                             result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
2039                     response.onResult(newResult);
2040                 } catch (RemoteException e) {
2041                     // if the caller is dead then there is no one to care about remote exceptions
2042                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
2043                         Log.v(TAG, "failure while notifying response", e);
2044                     }
2045                 }
2046             }
2047         }
2048 
2049         @Override
toDebugString(long now)2050         protected String toDebugString(long now) {
2051             return super.toDebugString(now) + ", hasFeatures"
2052                     + ", " + mAccount
2053                     + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
2054         }
2055     }
2056 
2057     @Override
renameAccount( IAccountManagerResponse response, Account accountToRename, String newName)2058     public void renameAccount(
2059             IAccountManagerResponse response, Account accountToRename, String newName) {
2060         final int callingUid = Binder.getCallingUid();
2061         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2062             Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
2063                 + ", caller's uid " + callingUid
2064                 + ", pid " + Binder.getCallingPid());
2065         }
2066         if (accountToRename == null) throw new IllegalArgumentException("account is null");
2067         int userId = UserHandle.getCallingUserId();
2068         if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
2069             String msg = String.format(
2070                     "uid %s cannot rename accounts of type: %s",
2071                     callingUid,
2072                     accountToRename.type);
2073             throw new SecurityException(msg);
2074         }
2075         final long identityToken = clearCallingIdentity();
2076         try {
2077             UserAccounts accounts = getUserAccounts(userId);
2078             Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
2079             Bundle result = new Bundle();
2080             result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
2081             result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
2082             result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
2083                     resultingAccount.getAccessId());
2084             try {
2085                 response.onResult(result);
2086             } catch (RemoteException e) {
2087                 Log.w(TAG, e.getMessage());
2088             }
2089         } finally {
2090             restoreCallingIdentity(identityToken);
2091         }
2092     }
2093 
renameAccountInternal( UserAccounts accounts, Account accountToRename, String newName)2094     private Account renameAccountInternal(
2095             UserAccounts accounts, Account accountToRename, String newName) {
2096         Account resultAccount = null;
2097         /*
2098          * Cancel existing notifications. Let authenticators
2099          * re-post notifications as required. But we don't know if
2100          * the authenticators have bound their notifications to
2101          * now stale account name data.
2102          *
2103          * With a rename api, we might not need to do this anymore but it
2104          * shouldn't hurt.
2105          */
2106         cancelNotification(
2107                 getSigninRequiredNotificationId(accounts, accountToRename),
2108                 new UserHandle(accounts.userId));
2109         synchronized(accounts.credentialsPermissionNotificationIds) {
2110             for (Pair<Pair<Account, String>, Integer> pair:
2111                     accounts.credentialsPermissionNotificationIds.keySet()) {
2112                 if (accountToRename.equals(pair.first.first)) {
2113                     NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
2114                     cancelNotification(id, new UserHandle(accounts.userId));
2115                 }
2116             }
2117         }
2118         synchronized (accounts.dbLock) {
2119             synchronized (accounts.cacheLock) {
2120                 List<String> accountRemovedReceivers =
2121                     getAccountRemovedReceivers(accountToRename, accounts);
2122                 accounts.accountsDb.beginTransaction();
2123                 Account renamedAccount = new Account(newName, accountToRename.type);
2124                 try {
2125                     if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
2126                         Log.e(TAG, "renameAccount failed - account with new name already exists");
2127                         return null;
2128                     }
2129                     final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2130                     if (accountId >= 0) {
2131                         accounts.accountsDb.renameCeAccount(accountId, newName);
2132                         if (accounts.accountsDb.renameDeAccount(
2133                                 accountId, newName, accountToRename.name)) {
2134                             accounts.accountsDb.setTransactionSuccessful();
2135                         } else {
2136                             Log.e(TAG, "renameAccount failed");
2137                             return null;
2138                         }
2139                     } else {
2140                         Log.e(TAG, "renameAccount failed - old account does not exist");
2141                         return null;
2142                     }
2143                 } finally {
2144                     accounts.accountsDb.endTransaction();
2145                 }
2146             /*
2147              * Database transaction was successful. Clean up cached
2148              * data associated with the account in the user profile.
2149              */
2150                 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
2151             /*
2152              * Extract the data and token caches before removing the
2153              * old account to preserve the user data associated with
2154              * the account.
2155              */
2156                 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2157                 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2158                 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2159                 removeAccountFromCacheLocked(accounts, accountToRename);
2160             /*
2161              * Update the cached data associated with the renamed
2162              * account.
2163              */
2164                 accounts.userDataCache.put(renamedAccount, tmpData);
2165                 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2166                 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2167                 accounts.previousNameCache.put(
2168                         renamedAccount,
2169                         new AtomicReference<>(accountToRename.name));
2170                 resultAccount = renamedAccount;
2171 
2172                 int parentUserId = accounts.userId;
2173                 if (canHaveProfile(parentUserId)) {
2174                 /*
2175                  * Owner or system user account was renamed, rename the account for
2176                  * those users with which the account was shared.
2177                  */
2178                     List<UserInfo> users = getUserManager().getAliveUsers();
2179                     for (UserInfo user : users) {
2180                         if (user.isRestricted()
2181                                 && (user.restrictedProfileParentId == parentUserId)) {
2182                             renameSharedAccountAsUser(accountToRename, newName, user.id);
2183                         }
2184                     }
2185                 }
2186 
2187                 sendNotificationAccountUpdated(resultAccount, accounts);
2188                 sendAccountsChangedBroadcast(accounts.userId);
2189                 for (String packageName : accountRemovedReceivers) {
2190                     sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2191                 }
2192 
2193                 AccountManager.invalidateLocalAccountsDataCaches();
2194                 AccountManager.invalidateLocalAccountUserDataCaches();
2195             }
2196         }
2197         return resultAccount;
2198     }
2199 
canHaveProfile(final int parentUserId)2200     private boolean canHaveProfile(final int parentUserId) {
2201         final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
2202         return userInfo != null && userInfo.canHaveProfile();
2203     }
2204 
2205     @Override
removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId)2206     public void removeAccountAsUser(IAccountManagerResponse response, Account account,
2207             boolean expectActivityLaunch, int userId) {
2208         final int callingUid = Binder.getCallingUid();
2209         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2210             Log.v(TAG, "removeAccount: " + account
2211                     + ", response " + response
2212                     + ", caller's uid " + callingUid
2213                     + ", pid " + Binder.getCallingPid()
2214                     + ", for user id " + userId);
2215         }
2216         Preconditions.checkArgument(account != null, "account cannot be null");
2217         Preconditions.checkArgument(response != null, "response cannot be null");
2218 
2219         // Only allow the system process to modify accounts of other users
2220         if (isCrossUser(callingUid, userId)) {
2221             throw new SecurityException(
2222                     String.format(
2223                             "User %s tying remove account for %s" ,
2224                             UserHandle.getCallingUserId(),
2225                             userId));
2226         }
2227         /*
2228          * Only the system, authenticator or profile owner should be allowed to remove accounts for
2229          * that authenticator.  This will let users remove accounts (via Settings in the system) but
2230          * not arbitrary applications (like competing authenticators).
2231          */
2232         UserHandle user = UserHandle.of(userId);
2233         if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
2234                 && !isSystemUid(callingUid)
2235                 && !isProfileOwner(callingUid)) {
2236             String msg = String.format(
2237                     "uid %s cannot remove accounts of type: %s",
2238                     callingUid,
2239                     account.type);
2240             throw new SecurityException(msg);
2241         }
2242         if (!canUserModifyAccounts(userId, callingUid)) {
2243             try {
2244                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2245                         "User cannot modify accounts");
2246             } catch (RemoteException re) {
2247             }
2248             return;
2249         }
2250         if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
2251             try {
2252                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2253                         "User cannot modify accounts of this type (policy).");
2254             } catch (RemoteException re) {
2255             }
2256             return;
2257         }
2258         final long identityToken = clearCallingIdentity();
2259         UserAccounts accounts = getUserAccounts(userId);
2260         cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
2261         synchronized(accounts.credentialsPermissionNotificationIds) {
2262             for (Pair<Pair<Account, String>, Integer> pair:
2263                 accounts.credentialsPermissionNotificationIds.keySet()) {
2264                 if (account.equals(pair.first.first)) {
2265                     NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
2266                     cancelNotification(id, user);
2267                 }
2268             }
2269         }
2270         final long accountId = accounts.accountsDb.findDeAccountId(account);
2271         logRecord(
2272                 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2273                 AccountsDb.TABLE_ACCOUNTS,
2274                 accountId,
2275                 accounts,
2276                 callingUid);
2277         try {
2278             new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2279         } finally {
2280             restoreCallingIdentity(identityToken);
2281         }
2282     }
2283 
2284     @Override
removeAccountExplicitly(Account account)2285     public boolean removeAccountExplicitly(Account account) {
2286         final int callingUid = Binder.getCallingUid();
2287         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2288             Log.v(TAG, "removeAccountExplicitly: " + account
2289                     + ", caller's uid " + callingUid
2290                     + ", pid " + Binder.getCallingPid());
2291         }
2292         int userId = Binder.getCallingUserHandle().getIdentifier();
2293         if (account == null) {
2294             /*
2295              * Null accounts should result in returning false, as per
2296              * AccountManage.addAccountExplicitly(...) java doc.
2297              */
2298             Log.e(TAG, "account is null");
2299             return false;
2300         } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2301             String msg = String.format(
2302                     "uid %s cannot explicitly remove accounts of type: %s",
2303                     callingUid,
2304                     account.type);
2305             throw new SecurityException(msg);
2306         }
2307         UserAccounts accounts = getUserAccountsForCaller();
2308         final long accountId = accounts.accountsDb.findDeAccountId(account);
2309         logRecord(
2310                 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2311                 AccountsDb.TABLE_ACCOUNTS,
2312                 accountId,
2313                 accounts,
2314                 callingUid);
2315         final long identityToken = clearCallingIdentity();
2316         try {
2317             return removeAccountInternal(accounts, account, callingUid);
2318         } finally {
2319             restoreCallingIdentity(identityToken);
2320         }
2321     }
2322 
2323     private class RemoveAccountSession extends Session {
2324         final Account mAccount;
RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response, Account account, boolean expectActivityLaunch)2325         public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
2326                 Account account, boolean expectActivityLaunch) {
2327             super(accounts, response, account.type, expectActivityLaunch,
2328                     true /* stripAuthTokenFromResult */, account.name,
2329                     false /* authDetailsRequired */);
2330             mAccount = account;
2331         }
2332 
2333         @Override
toDebugString(long now)2334         protected String toDebugString(long now) {
2335             return super.toDebugString(now) + ", removeAccount"
2336                     + ", account " + mAccount;
2337         }
2338 
2339         @Override
run()2340         public void run() throws RemoteException {
2341             mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2342         }
2343 
2344         @Override
onResult(Bundle result)2345         public void onResult(Bundle result) {
2346             Bundle.setDefusable(result, true);
2347             if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2348                     && !result.containsKey(AccountManager.KEY_INTENT)) {
2349                 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
2350                 if (removalAllowed) {
2351                     removeAccountInternal(mAccounts, mAccount, getCallingUid());
2352                 }
2353                 IAccountManagerResponse response = getResponseAndClose();
2354                 if (response != null) {
2355                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
2356                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2357                                 + response);
2358                     }
2359                     try {
2360                         response.onResult(result);
2361                     } catch (RemoteException e) {
2362                         Slog.e(TAG, "Error calling onResult()", e);
2363                     }
2364                 }
2365             }
2366             super.onResult(result);
2367         }
2368     }
2369 
2370     @VisibleForTesting
removeAccountInternal(Account account)2371     protected void removeAccountInternal(Account account) {
2372         removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
2373     }
2374 
removeAccountInternal(UserAccounts accounts, Account account, int callingUid)2375     private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
2376         boolean isChanged = false;
2377         boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
2378         if (!userUnlocked) {
2379             Slog.i(TAG, "Removing account " + account.toSafeString()
2380                     + " while user " + accounts.userId
2381                     + " is still locked. CE data will be removed later");
2382         }
2383         synchronized (accounts.dbLock) {
2384             synchronized (accounts.cacheLock) {
2385                 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2386                         accounts);
2387                 List<String> accountRemovedReceivers =
2388                     getAccountRemovedReceivers(account, accounts);
2389                 accounts.accountsDb.beginTransaction();
2390                 // Set to a placeholder value, this will only be used if the database
2391                 // transaction succeeds.
2392                 long accountId = -1;
2393                 try {
2394                     accountId = accounts.accountsDb.findDeAccountId(account);
2395                     if (accountId >= 0) {
2396                         isChanged = accounts.accountsDb.deleteDeAccount(accountId);
2397                     }
2398                     // always delete from CE table if CE storage is available
2399                     // DE account could be removed while CE was locked
2400                     if (userUnlocked) {
2401                         long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2402                         if (ceAccountId >= 0) {
2403                             accounts.accountsDb.deleteCeAccount(ceAccountId);
2404                         }
2405                     }
2406                     accounts.accountsDb.setTransactionSuccessful();
2407                 } finally {
2408                     accounts.accountsDb.endTransaction();
2409                 }
2410                 if (isChanged) {
2411                     removeAccountFromCacheLocked(accounts, account);
2412                     for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2413                             .entrySet()) {
2414                         if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2415                                 || (packageToVisibility.getValue()
2416                                     == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
2417                             notifyPackage(packageToVisibility.getKey(), accounts);
2418                         }
2419                     }
2420 
2421                     // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2422                     sendAccountsChangedBroadcast(accounts.userId);
2423                     for (String packageName : accountRemovedReceivers) {
2424                         sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2425                     }
2426                     String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2427                             : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2428                     logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2429                 }
2430             }
2431         }
2432         final long id = Binder.clearCallingIdentity();
2433         try {
2434             int parentUserId = accounts.userId;
2435             if (canHaveProfile(parentUserId)) {
2436                 // Remove from any restricted profiles that are sharing this account.
2437                 List<UserInfo> users = getUserManager().getAliveUsers();
2438                 for (UserInfo user : users) {
2439                     if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
2440                         removeSharedAccountAsUser(account, user.id, callingUid);
2441                     }
2442                 }
2443             }
2444         } finally {
2445             Binder.restoreCallingIdentity(id);
2446         }
2447 
2448         if (isChanged) {
2449             synchronized (accounts.credentialsPermissionNotificationIds) {
2450                 for (Pair<Pair<Account, String>, Integer> key
2451                         : accounts.credentialsPermissionNotificationIds.keySet()) {
2452                     if (account.equals(key.first.first)
2453                             && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
2454                         final int uid = (Integer) key.second;
2455                         mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
2456                                 account, uid, false));
2457                     }
2458                 }
2459             }
2460         }
2461 
2462         AccountManager.invalidateLocalAccountUserDataCaches();
2463 
2464         return isChanged;
2465     }
2466 
2467     @Override
invalidateAuthToken(String accountType, String authToken)2468     public void invalidateAuthToken(String accountType, String authToken) {
2469         int callerUid = Binder.getCallingUid();
2470         Objects.requireNonNull(accountType, "accountType cannot be null");
2471         Objects.requireNonNull(authToken, "authToken cannot be null");
2472         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2473             Log.v(TAG, "invalidateAuthToken: accountType " + accountType
2474                     + ", caller's uid " + callerUid
2475                     + ", pid " + Binder.getCallingPid());
2476         }
2477         int userId = UserHandle.getCallingUserId();
2478         final long identityToken = clearCallingIdentity();
2479         try {
2480             UserAccounts accounts = getUserAccounts(userId);
2481             List<Pair<Account, String>> deletedTokens;
2482             synchronized (accounts.dbLock) {
2483                 accounts.accountsDb.beginTransaction();
2484                 try {
2485                     deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2486                     accounts.accountsDb.setTransactionSuccessful();
2487                 } finally {
2488                     accounts.accountsDb.endTransaction();
2489                 }
2490                 synchronized (accounts.cacheLock) {
2491                     for (Pair<Account, String> tokenInfo : deletedTokens) {
2492                         Account act = tokenInfo.first;
2493                         String tokenType = tokenInfo.second;
2494                         writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
2495                     }
2496                     // wipe out cached token in memory.
2497                     accounts.accountTokenCaches.remove(accountType, authToken);
2498                 }
2499             }
2500         } finally {
2501             restoreCallingIdentity(identityToken);
2502         }
2503     }
2504 
invalidateAuthTokenLocked(UserAccounts accounts, String accountType, String authToken)2505     private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
2506             String authToken) {
2507         // TODO Move to AccountsDB
2508         List<Pair<Account, String>> results = new ArrayList<>();
2509         Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
2510 
2511         try {
2512             while (cursor.moveToNext()) {
2513                 String authTokenId = cursor.getString(0);
2514                 String accountName = cursor.getString(1);
2515                 String authTokenType = cursor.getString(2);
2516                 accounts.accountsDb.deleteAuthToken(authTokenId);
2517                 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
2518             }
2519         } finally {
2520             cursor.close();
2521         }
2522         return results;
2523     }
2524 
saveCachedToken( UserAccounts accounts, Account account, String callerPkg, byte[] callerSigDigest, String tokenType, String token, long expiryMillis)2525     private void saveCachedToken(
2526             UserAccounts accounts,
2527             Account account,
2528             String callerPkg,
2529             byte[] callerSigDigest,
2530             String tokenType,
2531             String token,
2532             long expiryMillis) {
2533 
2534         if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2535             return;
2536         }
2537         cancelNotification(getSigninRequiredNotificationId(accounts, account),
2538                 UserHandle.of(accounts.userId));
2539         synchronized (accounts.cacheLock) {
2540             accounts.accountTokenCaches.put(
2541                     account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
2542         }
2543     }
2544 
saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type, String authToken)2545     private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2546             String authToken) {
2547         if (account == null || type == null) {
2548             return false;
2549         }
2550         cancelNotification(getSigninRequiredNotificationId(accounts, account),
2551                 UserHandle.of(accounts.userId));
2552         synchronized (accounts.dbLock) {
2553             accounts.accountsDb.beginTransaction();
2554             boolean updateCache = false;
2555             try {
2556                 long accountId = accounts.accountsDb.findDeAccountId(account);
2557                 if (accountId < 0) {
2558                     return false;
2559                 }
2560                 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2561                 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2562                     accounts.accountsDb.setTransactionSuccessful();
2563                     updateCache = true;
2564                     return true;
2565                 }
2566                 return false;
2567             } finally {
2568                 accounts.accountsDb.endTransaction();
2569                 if (updateCache) {
2570                     synchronized (accounts.cacheLock) {
2571                         writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2572                     }
2573                 }
2574             }
2575         }
2576     }
2577 
2578     @Override
peekAuthToken(Account account, String authTokenType)2579     public String peekAuthToken(Account account, String authTokenType) {
2580         final int callingUid = Binder.getCallingUid();
2581         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2582             Log.v(TAG, "peekAuthToken: " + account
2583                     + ", authTokenType " + authTokenType
2584                     + ", caller's uid " + callingUid
2585                     + ", pid " + Binder.getCallingPid());
2586         }
2587         Objects.requireNonNull(account, "account cannot be null");
2588         Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
2589         int userId = UserHandle.getCallingUserId();
2590         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2591             String msg = String.format(
2592                     "uid %s cannot peek the authtokens associated with accounts of type: %s",
2593                     callingUid,
2594                     account.type);
2595             throw new SecurityException(msg);
2596         }
2597         if (!isLocalUnlockedUser(userId)) {
2598             Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2599                     + callingUid);
2600             return null;
2601         }
2602         final long identityToken = clearCallingIdentity();
2603         try {
2604             UserAccounts accounts = getUserAccounts(userId);
2605             return readAuthTokenInternal(accounts, account, authTokenType);
2606         } finally {
2607             restoreCallingIdentity(identityToken);
2608         }
2609     }
2610 
2611     @Override
setAuthToken(Account account, String authTokenType, String authToken)2612     public void setAuthToken(Account account, String authTokenType, String authToken) {
2613         final int callingUid = Binder.getCallingUid();
2614         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2615             Log.v(TAG, "setAuthToken: " + account
2616                     + ", authTokenType " + authTokenType
2617                     + ", caller's uid " + callingUid
2618                     + ", pid " + Binder.getCallingPid());
2619         }
2620         Objects.requireNonNull(account, "account cannot be null");
2621         Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
2622         int userId = UserHandle.getCallingUserId();
2623         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2624             String msg = String.format(
2625                     "uid %s cannot set auth tokens associated with accounts of type: %s",
2626                     callingUid,
2627                     account.type);
2628             throw new SecurityException(msg);
2629         }
2630         final long identityToken = clearCallingIdentity();
2631         try {
2632             UserAccounts accounts = getUserAccounts(userId);
2633             saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
2634         } finally {
2635             restoreCallingIdentity(identityToken);
2636         }
2637     }
2638 
2639     @Override
setPassword(Account account, String password)2640     public void setPassword(Account account, String password) {
2641         final int callingUid = Binder.getCallingUid();
2642         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2643             Log.v(TAG, "setAuthToken: " + account
2644                     + ", caller's uid " + callingUid
2645                     + ", pid " + Binder.getCallingPid());
2646         }
2647         Objects.requireNonNull(account, "account cannot be null");
2648         int userId = UserHandle.getCallingUserId();
2649         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2650             String msg = String.format(
2651                     "uid %s cannot set secrets for accounts of type: %s",
2652                     callingUid,
2653                     account.type);
2654             throw new SecurityException(msg);
2655         }
2656         final long identityToken = clearCallingIdentity();
2657         try {
2658             UserAccounts accounts = getUserAccounts(userId);
2659             setPasswordInternal(accounts, account, password, callingUid);
2660         } finally {
2661             restoreCallingIdentity(identityToken);
2662         }
2663     }
2664 
setPasswordInternal(UserAccounts accounts, Account account, String password, int callingUid)2665     private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2666             int callingUid) {
2667         if (account == null) {
2668             return;
2669         }
2670         boolean isChanged = false;
2671         synchronized (accounts.dbLock) {
2672             synchronized (accounts.cacheLock) {
2673                 accounts.accountsDb.beginTransaction();
2674                 try {
2675                     final long accountId = accounts.accountsDb.findDeAccountId(account);
2676                     if (accountId >= 0) {
2677                         accounts.accountsDb.updateCeAccountPassword(accountId, password);
2678                         accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2679                         accounts.authTokenCache.remove(account);
2680                         accounts.accountTokenCaches.remove(account);
2681                         accounts.accountsDb.setTransactionSuccessful();
2682                         // If there is an account whose password will be updated and the database
2683                         // transactions succeed, then we say that a change has occured. Even if the
2684                         // new password is the same as the old and there were no authtokens to
2685                         // delete.
2686                         isChanged = true;
2687                         String action = (password == null || password.length() == 0) ?
2688                                 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2689                                 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2690                         logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2691                                 callingUid);
2692                     }
2693                 } finally {
2694                     accounts.accountsDb.endTransaction();
2695                     if (isChanged) {
2696                         // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2697                         sendNotificationAccountUpdated(account, accounts);
2698                         sendAccountsChangedBroadcast(accounts.userId);
2699                     }
2700                 }
2701             }
2702         }
2703     }
2704 
2705     @Override
clearPassword(Account account)2706     public void clearPassword(Account account) {
2707         final int callingUid = Binder.getCallingUid();
2708         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2709             Log.v(TAG, "clearPassword: " + account
2710                     + ", caller's uid " + callingUid
2711                     + ", pid " + Binder.getCallingPid());
2712         }
2713         Objects.requireNonNull(account, "account cannot be null");
2714         int userId = UserHandle.getCallingUserId();
2715         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2716             String msg = String.format(
2717                     "uid %s cannot clear passwords for accounts of type: %s",
2718                     callingUid,
2719                     account.type);
2720             throw new SecurityException(msg);
2721         }
2722         final long identityToken = clearCallingIdentity();
2723         try {
2724             UserAccounts accounts = getUserAccounts(userId);
2725             setPasswordInternal(accounts, account, null, callingUid);
2726         } finally {
2727             restoreCallingIdentity(identityToken);
2728         }
2729     }
2730 
2731     @Override
setUserData(Account account, String key, String value)2732     public void setUserData(Account account, String key, String value) {
2733         final int callingUid = Binder.getCallingUid();
2734         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2735             Log.v(TAG, "setUserData: " + account
2736                     + ", key " + key
2737                     + ", caller's uid " + callingUid
2738                     + ", pid " + Binder.getCallingPid());
2739         }
2740         if (key == null) throw new IllegalArgumentException("key is null");
2741         if (account == null) throw new IllegalArgumentException("account is null");
2742         int userId = UserHandle.getCallingUserId();
2743         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
2744             String msg = String.format(
2745                     "uid %s cannot set user data for accounts of type: %s",
2746                     callingUid,
2747                     account.type);
2748             throw new SecurityException(msg);
2749         }
2750         final long identityToken = clearCallingIdentity();
2751         try {
2752             UserAccounts accounts = getUserAccounts(userId);
2753             if (!accountExistsCache(accounts, account)) {
2754                 return;
2755             }
2756             setUserdataInternal(accounts, account, key, value);
2757         } finally {
2758             restoreCallingIdentity(identityToken);
2759         }
2760     }
2761 
accountExistsCache(UserAccounts accounts, Account account)2762     private boolean accountExistsCache(UserAccounts accounts, Account account) {
2763         synchronized (accounts.cacheLock) {
2764             if (accounts.accountCache.containsKey(account.type)) {
2765                 for (Account acc : accounts.accountCache.get(account.type)) {
2766                     if (acc.name.equals(account.name)) {
2767                         return true;
2768                     }
2769                 }
2770             }
2771         }
2772         return false;
2773     }
2774 
setUserdataInternal(UserAccounts accounts, Account account, String key, String value)2775     private void setUserdataInternal(UserAccounts accounts, Account account, String key,
2776             String value) {
2777         synchronized (accounts.dbLock) {
2778             accounts.accountsDb.beginTransaction();
2779             try {
2780                 long accountId = accounts.accountsDb.findDeAccountId(account);
2781                 if (accountId < 0) {
2782                     return;
2783                 }
2784                 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2785                 if (extrasId < 0) {
2786                     extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2787                     if (extrasId < 0) {
2788                         return;
2789                     }
2790                 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2791                     return;
2792                 }
2793                 accounts.accountsDb.setTransactionSuccessful();
2794             } finally {
2795                 accounts.accountsDb.endTransaction();
2796             }
2797             synchronized (accounts.cacheLock) {
2798                 writeUserDataIntoCacheLocked(accounts, account, key, value);
2799                 AccountManager.invalidateLocalAccountUserDataCaches();
2800             }
2801         }
2802     }
2803 
onResult(IAccountManagerResponse response, Bundle result)2804     private void onResult(IAccountManagerResponse response, Bundle result) {
2805         if (result == null) {
2806             Log.e(TAG, "the result is unexpectedly null", new Exception());
2807         }
2808         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2809             Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2810                     + response);
2811         }
2812         try {
2813             response.onResult(result);
2814         } catch (RemoteException e) {
2815             // if the caller is dead then there is no one to care about remote
2816             // exceptions
2817             if (Log.isLoggable(TAG, Log.VERBOSE)) {
2818                 Log.v(TAG, "failure while notifying response", e);
2819             }
2820         }
2821     }
2822 
2823     @Override
getAuthTokenLabel(IAccountManagerResponse response, final String accountType, final String authTokenType)2824     public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2825                                   final String authTokenType)
2826             throws RemoteException {
2827         Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2828         Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
2829 
2830         final int callingUid = getCallingUid();
2831         clearCallingIdentity();
2832         if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
2833             throw new SecurityException("can only call from system");
2834         }
2835         int userId = UserHandle.getUserId(callingUid);
2836         final long identityToken = clearCallingIdentity();
2837         try {
2838             UserAccounts accounts = getUserAccounts(userId);
2839             new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2840                     false /* stripAuthTokenFromResult */,  null /* accountName */,
2841                     false /* authDetailsRequired */) {
2842                 @Override
2843                 protected String toDebugString(long now) {
2844                     return super.toDebugString(now) + ", getAuthTokenLabel"
2845                             + ", " + accountType
2846                             + ", authTokenType " + authTokenType;
2847                 }
2848 
2849                 @Override
2850                 public void run() throws RemoteException {
2851                     mAuthenticator.getAuthTokenLabel(this, authTokenType);
2852                 }
2853 
2854                 @Override
2855                 public void onResult(Bundle result) {
2856                     Bundle.setDefusable(result, true);
2857                     if (result != null) {
2858                         String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2859                         Bundle bundle = new Bundle();
2860                         bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2861                         super.onResult(bundle);
2862                         return;
2863                     } else {
2864                         super.onResult(result);
2865                     }
2866                 }
2867             }.bind();
2868         } finally {
2869             restoreCallingIdentity(identityToken);
2870         }
2871     }
2872 
2873     @Override
getAuthToken( IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, final boolean expectActivityLaunch, final Bundle loginOptions)2874     public void getAuthToken(
2875             IAccountManagerResponse response,
2876             final Account account,
2877             final String authTokenType,
2878             final boolean notifyOnAuthFailure,
2879             final boolean expectActivityLaunch,
2880             final Bundle loginOptions) {
2881         Bundle.setDefusable(loginOptions, true);
2882         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2883             Log.v(TAG, "getAuthToken: " + account
2884                     + ", response " + response
2885                     + ", authTokenType " + authTokenType
2886                     + ", notifyOnAuthFailure " + notifyOnAuthFailure
2887                     + ", expectActivityLaunch " + expectActivityLaunch
2888                     + ", caller's uid " + Binder.getCallingUid()
2889                     + ", pid " + Binder.getCallingPid());
2890         }
2891         Preconditions.checkArgument(response != null, "response cannot be null");
2892         try {
2893             if (account == null) {
2894                 Slog.w(TAG, "getAuthToken called with null account");
2895                 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2896                 return;
2897             }
2898             if (authTokenType == null) {
2899                 Slog.w(TAG, "getAuthToken called with null authTokenType");
2900                 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2901                 return;
2902             }
2903         } catch (RemoteException e) {
2904             Slog.w(TAG, "Failed to report error back to the client." + e);
2905             return;
2906         }
2907         int userId = UserHandle.getCallingUserId();
2908         final long ident = Binder.clearCallingIdentity();
2909         final UserAccounts accounts;
2910         final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
2911         try {
2912             accounts = getUserAccounts(userId);
2913             authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2914                     AuthenticatorDescription.newKey(account.type), accounts.userId);
2915         } finally {
2916             Binder.restoreCallingIdentity(ident);
2917         }
2918 
2919         final boolean customTokens =
2920                 authenticatorInfo != null && authenticatorInfo.type.customTokens;
2921 
2922         // skip the check if customTokens
2923         final int callerUid = Binder.getCallingUid();
2924         final boolean permissionGranted =
2925                 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
2926 
2927         // Get the calling package. We will use it for the purpose of caching.
2928         final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
2929         String[] callerOwnedPackageNames;
2930         final long ident2 = Binder.clearCallingIdentity();
2931         try {
2932             callerOwnedPackageNames = mPackageManager.getPackagesForUid(callerUid);
2933         } finally {
2934             Binder.restoreCallingIdentity(ident2);
2935         }
2936         if (callerPkg == null || callerOwnedPackageNames == null
2937                 || !ArrayUtils.contains(callerOwnedPackageNames, callerPkg)) {
2938             String msg = String.format(
2939                     "Uid %s is attempting to illegally masquerade as package %s!",
2940                     callerUid,
2941                     callerPkg);
2942             throw new SecurityException(msg);
2943         }
2944 
2945         // let authenticator know the identity of the caller
2946         loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2947         loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
2948 
2949         if (notifyOnAuthFailure) {
2950             loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
2951         }
2952 
2953         final long identityToken = clearCallingIdentity();
2954         try {
2955             // Distill the caller's package signatures into a single digest.
2956             final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2957 
2958             // if the caller has permission, do the peek. otherwise go the more expensive
2959             // route of starting a Session
2960             if (!customTokens && permissionGranted) {
2961                 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
2962                 if (authToken != null) {
2963                     logGetAuthTokenMetrics(callerPkg, account.type);
2964                     Bundle result = new Bundle();
2965                     result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2966                     result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2967                     result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2968                     onResult(response, result);
2969                     return;
2970                 }
2971             }
2972 
2973             if (customTokens) {
2974                 /*
2975                  * Look up tokens in the new cache only if the loginOptions don't have parameters
2976                  * outside of those expected to be injected by the AccountManager, e.g.
2977                  * ANDORID_PACKAGE_NAME.
2978                  */
2979                 String token = readCachedTokenInternal(
2980                         accounts,
2981                         account,
2982                         authTokenType,
2983                         callerPkg,
2984                         callerPkgSigDigest);
2985                 if (token != null) {
2986                     logGetAuthTokenMetrics(callerPkg, account.type);
2987                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
2988                         Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2989                     }
2990                     Bundle result = new Bundle();
2991                     result.putString(AccountManager.KEY_AUTHTOKEN, token);
2992                     result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2993                     result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2994                     onResult(response, result);
2995                     return;
2996                 }
2997             }
2998 
2999             new Session(
3000                     accounts,
3001                     response,
3002                     account.type,
3003                     expectActivityLaunch,
3004                     false /* stripAuthTokenFromResult */,
3005                     account.name,
3006                     false /* authDetailsRequired */) {
3007                 @Override
3008                 protected String toDebugString(long now) {
3009                     if (loginOptions != null) loginOptions.keySet();
3010                     return super.toDebugString(now) + ", getAuthToken"
3011                             + ", " + account.toSafeString()
3012                             + ", authTokenType " + authTokenType
3013                             + ", loginOptions " + loginOptions
3014                             + ", notifyOnAuthFailure " + notifyOnAuthFailure;
3015                 }
3016 
3017                 @Override
3018                 public void run() throws RemoteException {
3019                     // If the caller doesn't have permission then create and return the
3020                     // "grant permission" intent instead of the "getAuthToken" intent.
3021                     if (!permissionGranted) {
3022                         mAuthenticator.getAuthTokenLabel(this, authTokenType);
3023                     } else {
3024                         mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
3025                         logGetAuthTokenMetrics(callerPkg, account.type);
3026                     }
3027                 }
3028 
3029                 @Override
3030                 public void onResult(Bundle result) {
3031                     Bundle.setDefusable(result, true);
3032                     if (result != null) {
3033                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
3034                             Intent intent = newGrantCredentialsPermissionIntent(
3035                                     account,
3036                                     null,
3037                                     callerUid,
3038                                     new AccountAuthenticatorResponse(this),
3039                                     authTokenType,
3040                                     true);
3041                             Bundle bundle = new Bundle();
3042                             bundle.putParcelable(AccountManager.KEY_INTENT, intent);
3043                             onResult(bundle);
3044                             return;
3045                         }
3046                         String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
3047                         if (authToken != null) {
3048                             String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
3049                             String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
3050                             if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
3051                                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3052                                         "the type and name should not be empty");
3053                                 return;
3054                             }
3055                             Account resultAccount = new Account(name, type);
3056                             if (!customTokens) {
3057                                 saveAuthTokenToDatabase(
3058                                         mAccounts,
3059                                         resultAccount,
3060                                         authTokenType,
3061                                         authToken);
3062                             }
3063                             long expiryMillis = result.getLong(
3064                                     AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
3065                             if (customTokens
3066                                     && expiryMillis > System.currentTimeMillis()) {
3067                                 saveCachedToken(
3068                                         mAccounts,
3069                                         account,
3070                                         callerPkg,
3071                                         callerPkgSigDigest,
3072                                         authTokenType,
3073                                         authToken,
3074                                         expiryMillis);
3075                             }
3076                         }
3077 
3078                         Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
3079                         if (intent != null && notifyOnAuthFailure && !customTokens) {
3080                             /*
3081                              * Make sure that the supplied intent is owned by the authenticator
3082                              * giving it to the system. Otherwise a malicious authenticator could
3083                              * have users launching arbitrary activities by tricking users to
3084                              * interact with malicious notifications.
3085                              */
3086                             if (!checkKeyIntent(
3087                                     Binder.getCallingUid(),
3088                                     intent)) {
3089                                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3090                                         "invalid intent in bundle returned");
3091                                 return;
3092                             }
3093                             doNotification(
3094                                     mAccounts,
3095                                     account,
3096                                     result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
3097                                     intent, "android", accounts.userId);
3098                         }
3099                     }
3100                     super.onResult(result);
3101                 }
3102             }.bind();
3103         } finally {
3104             restoreCallingIdentity(identityToken);
3105         }
3106     }
3107 
logGetAuthTokenMetrics(final String callerPackage, String accountType)3108     private void logGetAuthTokenMetrics(final String callerPackage, String accountType) {
3109         // Although this is not a 'device policy' API, enterprise is the current use case.
3110         DevicePolicyEventLogger
3111                 .createEvent(DevicePolicyEnums.GET_ACCOUNT_AUTH_TOKEN)
3112                 .setStrings(
3113                         TextUtils.emptyIfNull(callerPackage),
3114                         TextUtils.emptyIfNull(accountType))
3115                 .write();
3116     }
3117 
calculatePackageSignatureDigest(String callerPkg)3118     private byte[] calculatePackageSignatureDigest(String callerPkg) {
3119         MessageDigest digester;
3120         try {
3121             digester = MessageDigest.getInstance("SHA-256");
3122             PackageInfo pkgInfo = mPackageManager.getPackageInfo(
3123                     callerPkg, PackageManager.GET_SIGNATURES);
3124             for (Signature sig : pkgInfo.signatures) {
3125                 digester.update(sig.toByteArray());
3126             }
3127         } catch (NoSuchAlgorithmException x) {
3128             Log.wtf(TAG, "SHA-256 should be available", x);
3129             digester = null;
3130         } catch (NameNotFoundException e) {
3131             Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
3132             digester = null;
3133         }
3134         return (digester == null) ? null : digester.digest();
3135     }
3136 
createNoCredentialsPermissionNotification(Account account, Intent intent, String packageName, int userId)3137     private void createNoCredentialsPermissionNotification(Account account, Intent intent,
3138             String packageName, int userId) {
3139         int uid = intent.getIntExtra(
3140                 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3141         String authTokenType = intent.getStringExtra(
3142                 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
3143         final String titleAndSubtitle =
3144                 mContext.getString(R.string.permission_request_notification_for_app_with_subtitle,
3145                 getApplicationLabel(packageName), account.name);
3146         final int index = titleAndSubtitle.indexOf('\n');
3147         String title = titleAndSubtitle;
3148         String subtitle = "";
3149         if (index > 0) {
3150             title = titleAndSubtitle.substring(0, index);
3151             subtitle = titleAndSubtitle.substring(index + 1);
3152         }
3153         UserHandle user = UserHandle.of(userId);
3154         Context contextForUser = getContextForUser(user);
3155         Notification n =
3156                 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3157                     .setSmallIcon(android.R.drawable.stat_sys_warning)
3158                     .setWhen(0)
3159                     .setColor(contextForUser.getColor(
3160                             com.android.internal.R.color.system_notification_accent_color))
3161                     .setContentTitle(title)
3162                     .setContentText(subtitle)
3163                     .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3164                             PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3165                             null, user))
3166                     .build();
3167         installNotification(getCredentialPermissionNotificationId(
3168                 account, authTokenType, uid), n, "android", user.getIdentifier());
3169     }
3170 
getApplicationLabel(String packageName)3171     private String getApplicationLabel(String packageName) {
3172         try {
3173             return mPackageManager.getApplicationLabel(
3174                     mPackageManager.getApplicationInfo(packageName, 0)).toString();
3175         } catch (PackageManager.NameNotFoundException e) {
3176             return packageName;
3177         }
3178     }
3179 
newGrantCredentialsPermissionIntent(Account account, String packageName, int uid, AccountAuthenticatorResponse response, String authTokenType, boolean startInNewTask)3180     private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3181             int uid, AccountAuthenticatorResponse response, String authTokenType,
3182             boolean startInNewTask) {
3183 
3184         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
3185 
3186         if (startInNewTask) {
3187             // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3188             // Since it was set in Eclair+ we can't change it without breaking apps using
3189             // the intent from a non-Activity context. This is the default behavior.
3190             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3191         }
3192         intent.addCategory(getCredentialPermissionNotificationId(account,
3193                 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
3194         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
3195         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3196         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
3197         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
3198 
3199         return intent;
3200     }
3201 
getCredentialPermissionNotificationId(Account account, String authTokenType, int uid)3202     private NotificationId getCredentialPermissionNotificationId(Account account,
3203             String authTokenType, int uid) {
3204         NotificationId nId;
3205         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
3206         synchronized (accounts.credentialsPermissionNotificationIds) {
3207             final Pair<Pair<Account, String>, Integer> key =
3208                     new Pair<Pair<Account, String>, Integer>(
3209                             new Pair<Account, String>(account, authTokenType), uid);
3210             nId = accounts.credentialsPermissionNotificationIds.get(key);
3211             if (nId == null) {
3212                 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3213                         + ":" + account.hashCode() + ":" + authTokenType.hashCode() + ":" + uid;
3214                 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3215                 nId = new NotificationId(tag, id);
3216                 accounts.credentialsPermissionNotificationIds.put(key, nId);
3217             }
3218         }
3219         return nId;
3220     }
3221 
getSigninRequiredNotificationId(UserAccounts accounts, Account account)3222     private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3223         NotificationId nId;
3224         synchronized (accounts.signinRequiredNotificationIds) {
3225             nId = accounts.signinRequiredNotificationIds.get(account);
3226             if (nId == null) {
3227                 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3228                         + ":" + account.hashCode();
3229                 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3230                 nId = new NotificationId(tag, id);
3231                 accounts.signinRequiredNotificationIds.put(account, nId);
3232             }
3233         }
3234         return nId;
3235     }
3236 
3237     @Override
addAccount(final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn)3238     public void addAccount(final IAccountManagerResponse response, final String accountType,
3239             final String authTokenType, final String[] requiredFeatures,
3240             final boolean expectActivityLaunch, final Bundle optionsIn) {
3241         Bundle.setDefusable(optionsIn, true);
3242         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3243             Log.v(TAG, "addAccount: accountType " + accountType
3244                     + ", response " + response
3245                     + ", authTokenType " + authTokenType
3246                     + ", requiredFeatures " + Arrays.toString(requiredFeatures)
3247                     + ", expectActivityLaunch " + expectActivityLaunch
3248                     + ", caller's uid " + Binder.getCallingUid()
3249                     + ", pid " + Binder.getCallingPid());
3250         }
3251         if (response == null) throw new IllegalArgumentException("response is null");
3252         if (accountType == null) throw new IllegalArgumentException("accountType is null");
3253 
3254         // Is user disallowed from modifying accounts?
3255         final int uid = Binder.getCallingUid();
3256         final int userId = UserHandle.getUserId(uid);
3257         if (!canUserModifyAccounts(userId, uid)) {
3258             try {
3259                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3260                         "User is not allowed to add an account!");
3261             } catch (RemoteException re) {
3262             }
3263             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3264             return;
3265         }
3266         if (!canUserModifyAccountsForType(userId, accountType, uid)) {
3267             try {
3268                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3269                         "User cannot modify accounts of this type (policy).");
3270             } catch (RemoteException re) {
3271             }
3272             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3273                     userId);
3274             return;
3275         }
3276         addAccountAndLogMetrics(response, accountType, authTokenType, requiredFeatures,
3277                 expectActivityLaunch, optionsIn, userId);
3278     }
3279 
3280     @Override
addAccountAsUser(final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn, int userId)3281     public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3282             final String authTokenType, final String[] requiredFeatures,
3283             final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
3284         Bundle.setDefusable(optionsIn, true);
3285         int callingUid = Binder.getCallingUid();
3286         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3287             Log.v(TAG, "addAccount: accountType " + accountType
3288                     + ", response " + response
3289                     + ", authTokenType " + authTokenType
3290                     + ", requiredFeatures " + Arrays.toString(requiredFeatures)
3291                     + ", expectActivityLaunch " + expectActivityLaunch
3292                     + ", caller's uid " + Binder.getCallingUid()
3293                     + ", pid " + Binder.getCallingPid()
3294                     + ", for user id " + userId);
3295         }
3296         Preconditions.checkArgument(response != null, "response cannot be null");
3297         Preconditions.checkArgument(accountType != null, "accountType cannot be null");
3298         // Only allow the system process to add accounts of other users
3299         if (isCrossUser(callingUid, userId)) {
3300             throw new SecurityException(
3301                     String.format(
3302                             "User %s trying to add account for %s" ,
3303                             UserHandle.getCallingUserId(),
3304                             userId));
3305         }
3306 
3307         // Is user disallowed from modifying accounts?
3308         if (!canUserModifyAccounts(userId, callingUid)) {
3309             try {
3310                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3311                         "User is not allowed to add an account!");
3312             } catch (RemoteException re) {
3313             }
3314             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3315             return;
3316         }
3317         if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
3318             try {
3319                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3320                         "User cannot modify accounts of this type (policy).");
3321             } catch (RemoteException re) {
3322             }
3323             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3324                     userId);
3325             return;
3326         }
3327         addAccountAndLogMetrics(response, accountType, authTokenType, requiredFeatures,
3328                 expectActivityLaunch, optionsIn, userId);
3329     }
3330 
addAccountAndLogMetrics( IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle optionsIn, int userId)3331     private void addAccountAndLogMetrics(
3332             IAccountManagerResponse response, String accountType,
3333             String authTokenType, String[] requiredFeatures,
3334             boolean expectActivityLaunch, Bundle optionsIn, int userId) {
3335         final int pid = Binder.getCallingPid();
3336         final int uid = Binder.getCallingUid();
3337         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3338         options.putInt(AccountManager.KEY_CALLER_UID, uid);
3339         options.putInt(AccountManager.KEY_CALLER_PID, pid);
3340 
3341         final long identityToken = clearCallingIdentity();
3342         try {
3343             UserAccounts accounts = getUserAccounts(userId);
3344             logRecordWithUid(
3345                     accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3346                     uid);
3347             new Session(accounts, response, accountType, expectActivityLaunch,
3348                     true /* stripAuthTokenFromResult */, null /* accountName */,
3349                     false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
3350                 @Override
3351                 public void run() throws RemoteException {
3352                     mAuthenticator.addAccount(
3353                             this, mAccountType, authTokenType, requiredFeatures, options);
3354                     String callerPackage = options.getString(
3355                             AccountManager.KEY_ANDROID_PACKAGE_NAME);
3356                     logAddAccountMetrics(
3357                             callerPackage, accountType, requiredFeatures, authTokenType);
3358                 }
3359 
3360                 @Override
3361                 protected String toDebugString(long now) {
3362                     return super.toDebugString(now) + ", addAccount"
3363                             + ", accountType " + accountType
3364                             + ", requiredFeatures "
3365                             + (requiredFeatures != null
3366                             ? TextUtils.join(",", requiredFeatures)
3367                             : null);
3368                 }
3369             }.bind();
3370         } finally {
3371             restoreCallingIdentity(identityToken);
3372         }
3373     }
3374 
logAddAccountMetrics( String callerPackage, String accountType, String[] requiredFeatures, String authTokenType)3375     private void logAddAccountMetrics(
3376             String callerPackage, String accountType, String[] requiredFeatures,
3377             String authTokenType) {
3378         // Although this is not a 'device policy' API, enterprise is the current use case.
3379         DevicePolicyEventLogger
3380                 .createEvent(DevicePolicyEnums.ADD_ACCOUNT)
3381                 .setStrings(
3382                         TextUtils.emptyIfNull(accountType),
3383                         TextUtils.emptyIfNull(callerPackage),
3384                         TextUtils.emptyIfNull(authTokenType),
3385                         requiredFeatures == null
3386                                 ? ""
3387                                 : TextUtils.join(";", requiredFeatures))
3388                 .write();
3389     }
3390 
3391     @Override
startAddAccountSession( final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn)3392     public void startAddAccountSession(
3393             final IAccountManagerResponse response,
3394             final String accountType,
3395             final String authTokenType,
3396             final String[] requiredFeatures,
3397             final boolean expectActivityLaunch,
3398             final Bundle optionsIn) {
3399         Bundle.setDefusable(optionsIn, true);
3400         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3401             Log.v(TAG,
3402                     "startAddAccountSession: accountType " + accountType
3403                     + ", response " + response
3404                     + ", authTokenType " + authTokenType
3405                     + ", requiredFeatures " + Arrays.toString(requiredFeatures)
3406                     + ", expectActivityLaunch " + expectActivityLaunch
3407                     + ", caller's uid " + Binder.getCallingUid()
3408                     + ", pid " + Binder.getCallingPid());
3409         }
3410         Preconditions.checkArgument(response != null, "response cannot be null");
3411         Preconditions.checkArgument(accountType != null, "accountType cannot be null");
3412 
3413         final int uid = Binder.getCallingUid();
3414         final int userId = UserHandle.getUserId(uid);
3415         if (!canUserModifyAccounts(userId, uid)) {
3416             try {
3417                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3418                         "User is not allowed to add an account!");
3419             } catch (RemoteException re) {
3420             }
3421             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3422             return;
3423         }
3424         if (!canUserModifyAccountsForType(userId, accountType, uid)) {
3425             try {
3426                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3427                         "User cannot modify accounts of this type (policy).");
3428             } catch (RemoteException re) {
3429             }
3430             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3431                     userId);
3432             return;
3433         }
3434         final int pid = Binder.getCallingPid();
3435         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3436         options.putInt(AccountManager.KEY_CALLER_UID, uid);
3437         options.putInt(AccountManager.KEY_CALLER_PID, pid);
3438 
3439         // Check to see if the Password should be included to the caller.
3440         String callerPkg = options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3441         boolean isPasswordForwardingAllowed = checkPermissionAndNote(
3442                 callerPkg, uid, Manifest.permission.GET_PASSWORD);
3443 
3444         final long identityToken = clearCallingIdentity();
3445         try {
3446             UserAccounts accounts = getUserAccounts(userId);
3447             logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3448                     AccountsDb.TABLE_ACCOUNTS, uid);
3449             new StartAccountSession(
3450                     accounts,
3451                     response,
3452                     accountType,
3453                     expectActivityLaunch,
3454                     null /* accountName */,
3455                     false /* authDetailsRequired */,
3456                     true /* updateLastAuthenticationTime */,
3457                     isPasswordForwardingAllowed) {
3458                 @Override
3459                 public void run() throws RemoteException {
3460                     mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3461                             requiredFeatures, options);
3462                     logAddAccountMetrics(callerPkg, accountType, requiredFeatures, authTokenType);
3463                 }
3464 
3465                 @Override
3466                 protected String toDebugString(long now) {
3467                     String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3468                     return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3469                             + accountType + ", requiredFeatures "
3470                             + (requiredFeatures != null ? requiredFeaturesStr : null);
3471                 }
3472             }.bind();
3473         } finally {
3474             restoreCallingIdentity(identityToken);
3475         }
3476     }
3477 
3478     /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3479     private abstract class StartAccountSession extends Session {
3480 
3481         private final boolean mIsPasswordForwardingAllowed;
3482 
StartAccountSession( UserAccounts accounts, IAccountManagerResponse response, String accountType, boolean expectActivityLaunch, String accountName, boolean authDetailsRequired, boolean updateLastAuthenticationTime, boolean isPasswordForwardingAllowed)3483         public StartAccountSession(
3484                 UserAccounts accounts,
3485                 IAccountManagerResponse response,
3486                 String accountType,
3487                 boolean expectActivityLaunch,
3488                 String accountName,
3489                 boolean authDetailsRequired,
3490                 boolean updateLastAuthenticationTime,
3491                 boolean isPasswordForwardingAllowed) {
3492             super(accounts, response, accountType, expectActivityLaunch,
3493                     true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3494                     updateLastAuthenticationTime);
3495             mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
3496         }
3497 
3498         @Override
onResult(Bundle result)3499         public void onResult(Bundle result) {
3500             Bundle.setDefusable(result, true);
3501             mNumResults++;
3502             Intent intent = null;
3503             if (result != null
3504                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
3505                 if (!checkKeyIntent(
3506                         Binder.getCallingUid(),
3507                         intent)) {
3508                     onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3509                             "invalid intent in bundle returned");
3510                     return;
3511                 }
3512             }
3513             IAccountManagerResponse response;
3514             if (mExpectActivityLaunch && result != null
3515                     && result.containsKey(AccountManager.KEY_INTENT)) {
3516                 response = mResponse;
3517             } else {
3518                 response = getResponseAndClose();
3519             }
3520             if (response == null) {
3521                 return;
3522             }
3523             if (result == null) {
3524                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3525                     Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3526                             + response);
3527                 }
3528                 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3529                         "null bundle returned");
3530                 return;
3531             }
3532 
3533             if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3534                 // All AccountManager error codes are greater
3535                 // than 0
3536                 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3537                         result.getString(AccountManager.KEY_ERROR_MESSAGE));
3538                 return;
3539             }
3540 
3541             // Omit passwords if the caller isn't permitted to see them.
3542             if (!mIsPasswordForwardingAllowed) {
3543                 result.remove(AccountManager.KEY_PASSWORD);
3544             }
3545 
3546             // Strip auth token from result.
3547             result.remove(AccountManager.KEY_AUTHTOKEN);
3548 
3549             if (Log.isLoggable(TAG, Log.VERBOSE)) {
3550                 Log.v(TAG,
3551                         getClass().getSimpleName() + " calling onResult() on response " + response);
3552             }
3553 
3554             // Get the session bundle created by authenticator. The
3555             // bundle contains data necessary for finishing the session
3556             // later. The session bundle will be encrypted here and
3557             // decrypted later when trying to finish the session.
3558             Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3559             if (sessionBundle != null) {
3560                 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3561                 if (TextUtils.isEmpty(accountType)
3562                         || !mAccountType.equalsIgnoreCase(accountType)) {
3563                     Log.w(TAG, "Account type in session bundle doesn't match request.");
3564                 }
3565                 // Add accountType info to session bundle. This will
3566                 // override any value set by authenticator.
3567                 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3568 
3569                 // Encrypt session bundle before returning to caller.
3570                 try {
3571                     CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3572                     Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3573                     result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3574                 } catch (GeneralSecurityException e) {
3575                     if (Log.isLoggable(TAG, Log.DEBUG)) {
3576                         Log.v(TAG, "Failed to encrypt session bundle!", e);
3577                     }
3578                     sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3579                             "failed to encrypt session bundle");
3580                     return;
3581                 }
3582             }
3583 
3584             sendResponse(response, result);
3585         }
3586     }
3587 
3588     @Override
finishSessionAsUser(IAccountManagerResponse response, @NonNull Bundle sessionBundle, boolean expectActivityLaunch, Bundle appInfo, int userId)3589     public void finishSessionAsUser(IAccountManagerResponse response,
3590             @NonNull Bundle sessionBundle,
3591             boolean expectActivityLaunch,
3592             Bundle appInfo,
3593             int userId) {
3594         Bundle.setDefusable(sessionBundle, true);
3595         int callingUid = Binder.getCallingUid();
3596         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3597             Log.v(TAG,
3598                     "finishSession: response "+ response
3599                             + ", expectActivityLaunch " + expectActivityLaunch
3600                             + ", caller's uid " + callingUid
3601                             + ", caller's user id " + UserHandle.getCallingUserId()
3602                             + ", pid " + Binder.getCallingPid()
3603                             + ", for user id " + userId);
3604         }
3605         Preconditions.checkArgument(response != null, "response cannot be null");
3606         // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3607         // Account type is added to it before encryption.
3608         if (sessionBundle == null || sessionBundle.size() == 0) {
3609             throw new IllegalArgumentException("sessionBundle is empty");
3610         }
3611 
3612         // Only allow the system process to finish session for other users.
3613         if (isCrossUser(callingUid, userId)) {
3614             throw new SecurityException(
3615                     String.format(
3616                             "User %s trying to finish session for %s without cross user permission",
3617                             UserHandle.getCallingUserId(),
3618                             userId));
3619         }
3620 
3621         if (!canUserModifyAccounts(userId, callingUid)) {
3622             sendErrorResponse(response,
3623                     AccountManager.ERROR_CODE_USER_RESTRICTED,
3624                     "User is not allowed to add an account!");
3625             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3626             return;
3627         }
3628 
3629         final int pid = Binder.getCallingPid();
3630         final Bundle decryptedBundle;
3631         final String accountType;
3632         // First decrypt session bundle to get account type for checking permission.
3633         try {
3634             CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3635             decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3636             if (decryptedBundle == null) {
3637                 sendErrorResponse(
3638                         response,
3639                         AccountManager.ERROR_CODE_BAD_REQUEST,
3640                         "failed to decrypt session bundle");
3641                 return;
3642             }
3643             accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3644             // Account type cannot be null. This should not happen if session bundle was created
3645             // properly by #StartAccountSession.
3646             if (TextUtils.isEmpty(accountType)) {
3647                 sendErrorResponse(
3648                         response,
3649                         AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3650                         "accountType is empty");
3651                 return;
3652             }
3653 
3654             // If by any chances, decryptedBundle contains colliding keys with
3655             // system info
3656             // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3657             // update credentials flow, we should replace with the new values of the current call.
3658             if (appInfo != null) {
3659                 decryptedBundle.putAll(appInfo);
3660             }
3661 
3662             // Add info that may be used by add account or update credentials flow.
3663             decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
3664             decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3665         } catch (GeneralSecurityException e) {
3666             if (Log.isLoggable(TAG, Log.DEBUG)) {
3667                 Log.v(TAG, "Failed to decrypt session bundle!", e);
3668             }
3669             sendErrorResponse(
3670                     response,
3671                     AccountManager.ERROR_CODE_BAD_REQUEST,
3672                     "failed to decrypt session bundle");
3673             return;
3674         }
3675 
3676         if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
3677             sendErrorResponse(
3678                     response,
3679                     AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3680                     "User cannot modify accounts of this type (policy).");
3681             showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3682                     userId);
3683             return;
3684         }
3685 
3686         final long identityToken = clearCallingIdentity();
3687         try {
3688             UserAccounts accounts = getUserAccounts(userId);
3689             logRecordWithUid(
3690                     accounts,
3691                     AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3692                     AccountsDb.TABLE_ACCOUNTS,
3693                     callingUid);
3694             new Session(
3695                     accounts,
3696                     response,
3697                     accountType,
3698                     expectActivityLaunch,
3699                     true /* stripAuthTokenFromResult */,
3700                     null /* accountName */,
3701                     false /* authDetailsRequired */,
3702                     true /* updateLastAuthenticationTime */) {
3703                 @Override
3704                 public void run() throws RemoteException {
3705                     mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3706                 }
3707 
3708                 @Override
3709                 protected String toDebugString(long now) {
3710                     return super.toDebugString(now)
3711                             + ", finishSession"
3712                             + ", accountType " + accountType;
3713                 }
3714             }.bind();
3715         } finally {
3716             restoreCallingIdentity(identityToken);
3717         }
3718     }
3719 
showCantAddAccount(int errorCode, int userId)3720     private void showCantAddAccount(int errorCode, int userId) {
3721         final DevicePolicyManagerInternal dpmi =
3722                 LocalServices.getService(DevicePolicyManagerInternal.class);
3723         Intent intent = null;
3724         if (dpmi == null) {
3725             intent = getDefaultCantAddAccountIntent(errorCode);
3726         } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
3727             intent = dpmi.createUserRestrictionSupportIntent(userId,
3728                     UserManager.DISALLOW_MODIFY_ACCOUNTS);
3729         } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3730             intent = dpmi.createShowAdminSupportIntent(userId, false);
3731         }
3732         if (intent == null) {
3733             intent = getDefaultCantAddAccountIntent(errorCode);
3734         }
3735         final long identityToken = clearCallingIdentity();
3736         try {
3737             mContext.startActivityAsUser(intent, new UserHandle(userId));
3738         } finally {
3739             restoreCallingIdentity(identityToken);
3740         }
3741     }
3742 
3743     /**
3744      * Called when we don't know precisely who is preventing us from adding an account.
3745      */
getDefaultCantAddAccountIntent(int errorCode)3746     private Intent getDefaultCantAddAccountIntent(int errorCode) {
3747         Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3748         cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3749         cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3750         return cantAddAccount;
3751     }
3752 
3753     @Override
confirmCredentialsAsUser( IAccountManagerResponse response, final Account account, final Bundle options, final boolean expectActivityLaunch, int userId)3754     public void confirmCredentialsAsUser(
3755             IAccountManagerResponse response,
3756             final Account account,
3757             final Bundle options,
3758             final boolean expectActivityLaunch,
3759             int userId) {
3760         Bundle.setDefusable(options, true);
3761         int callingUid = Binder.getCallingUid();
3762         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3763             Log.v(TAG, "confirmCredentials: " + account
3764                     + ", response " + response
3765                     + ", expectActivityLaunch " + expectActivityLaunch
3766                     + ", caller's uid " + callingUid
3767                     + ", pid " + Binder.getCallingPid());
3768         }
3769         // Only allow the system process to read accounts of other users
3770         if (isCrossUser(callingUid, userId)) {
3771             throw new SecurityException(
3772                     String.format(
3773                             "User %s trying to confirm account credentials for %s" ,
3774                             UserHandle.getCallingUserId(),
3775                             userId));
3776         }
3777         if (response == null) throw new IllegalArgumentException("response is null");
3778         if (account == null) throw new IllegalArgumentException("account is null");
3779         final long identityToken = clearCallingIdentity();
3780         try {
3781             UserAccounts accounts = getUserAccounts(userId);
3782             new Session(accounts, response, account.type, expectActivityLaunch,
3783                     true /* stripAuthTokenFromResult */, account.name,
3784                     true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
3785                 @Override
3786                 public void run() throws RemoteException {
3787                     mAuthenticator.confirmCredentials(this, account, options);
3788                 }
3789                 @Override
3790                 protected String toDebugString(long now) {
3791                     return super.toDebugString(now) + ", confirmCredentials"
3792                             + ", " + account.toSafeString();
3793                 }
3794             }.bind();
3795         } finally {
3796             restoreCallingIdentity(identityToken);
3797         }
3798     }
3799 
3800     @Override
updateCredentials(IAccountManagerResponse response, final Account account, final String authTokenType, final boolean expectActivityLaunch, final Bundle loginOptions)3801     public void updateCredentials(IAccountManagerResponse response, final Account account,
3802             final String authTokenType, final boolean expectActivityLaunch,
3803             final Bundle loginOptions) {
3804         Bundle.setDefusable(loginOptions, true);
3805         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3806             Log.v(TAG, "updateCredentials: " + account
3807                     + ", response " + response
3808                     + ", authTokenType " + authTokenType
3809                     + ", expectActivityLaunch " + expectActivityLaunch
3810                     + ", caller's uid " + Binder.getCallingUid()
3811                     + ", pid " + Binder.getCallingPid());
3812         }
3813         if (response == null) throw new IllegalArgumentException("response is null");
3814         if (account == null) throw new IllegalArgumentException("account is null");
3815         int userId = UserHandle.getCallingUserId();
3816         final long identityToken = clearCallingIdentity();
3817         try {
3818             UserAccounts accounts = getUserAccounts(userId);
3819             new Session(accounts, response, account.type, expectActivityLaunch,
3820                     true /* stripAuthTokenFromResult */, account.name,
3821                     false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
3822                 @Override
3823                 public void run() throws RemoteException {
3824                     mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3825                 }
3826                 @Override
3827                 protected String toDebugString(long now) {
3828                     if (loginOptions != null) loginOptions.keySet();
3829                     return super.toDebugString(now) + ", updateCredentials"
3830                             + ", " + account.toSafeString()
3831                             + ", authTokenType " + authTokenType
3832                             + ", loginOptions " + loginOptions;
3833                 }
3834             }.bind();
3835         } finally {
3836             restoreCallingIdentity(identityToken);
3837         }
3838     }
3839 
3840     @Override
startUpdateCredentialsSession( IAccountManagerResponse response, final Account account, final String authTokenType, final boolean expectActivityLaunch, final Bundle loginOptions)3841     public void startUpdateCredentialsSession(
3842             IAccountManagerResponse response,
3843             final Account account,
3844             final String authTokenType,
3845             final boolean expectActivityLaunch,
3846             final Bundle loginOptions) {
3847         Bundle.setDefusable(loginOptions, true);
3848         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3849             Log.v(TAG,
3850                     "startUpdateCredentialsSession: " + account + ", response " + response
3851                             + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3852                             + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3853                             + ", pid " + Binder.getCallingPid());
3854         }
3855         if (response == null) {
3856             throw new IllegalArgumentException("response is null");
3857         }
3858         if (account == null) {
3859             throw new IllegalArgumentException("account is null");
3860         }
3861 
3862         final int uid = Binder.getCallingUid();
3863         int userId = UserHandle.getCallingUserId();
3864 
3865         // Check to see if the Password should be included to the caller.
3866         String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3867         boolean isPasswordForwardingAllowed = checkPermissionAndNote(
3868                 callerPkg, uid, Manifest.permission.GET_PASSWORD);
3869 
3870         final long identityToken = clearCallingIdentity();
3871         try {
3872             UserAccounts accounts = getUserAccounts(userId);
3873             new StartAccountSession(
3874                     accounts,
3875                     response,
3876                     account.type,
3877                     expectActivityLaunch,
3878                     account.name,
3879                     false /* authDetailsRequired */,
3880                     true /* updateLastCredentialTime */,
3881                     isPasswordForwardingAllowed) {
3882                 @Override
3883                 public void run() throws RemoteException {
3884                     mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3885                             loginOptions);
3886                 }
3887 
3888                 @Override
3889                 protected String toDebugString(long now) {
3890                     if (loginOptions != null)
3891                         loginOptions.keySet();
3892                     return super.toDebugString(now)
3893                             + ", startUpdateCredentialsSession"
3894                             + ", " + account.toSafeString()
3895                             + ", authTokenType " + authTokenType
3896                             + ", loginOptions " + loginOptions;
3897                 }
3898             }.bind();
3899         } finally {
3900             restoreCallingIdentity(identityToken);
3901         }
3902     }
3903 
3904     @Override
isCredentialsUpdateSuggested( IAccountManagerResponse response, final Account account, final String statusToken)3905     public void isCredentialsUpdateSuggested(
3906             IAccountManagerResponse response,
3907             final Account account,
3908             final String statusToken) {
3909         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3910             Log.v(TAG,
3911                     "isCredentialsUpdateSuggested: " + account + ", response " + response
3912                             + ", caller's uid " + Binder.getCallingUid()
3913                             + ", pid " + Binder.getCallingPid());
3914         }
3915         if (response == null) {
3916             throw new IllegalArgumentException("response is null");
3917         }
3918         if (account == null) {
3919             throw new IllegalArgumentException("account is null");
3920         }
3921         if (TextUtils.isEmpty(statusToken)) {
3922             throw new IllegalArgumentException("status token is empty");
3923         }
3924 
3925         int usrId = UserHandle.getCallingUserId();
3926         final long identityToken = clearCallingIdentity();
3927         try {
3928             UserAccounts accounts = getUserAccounts(usrId);
3929             new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3930                     false /* stripAuthTokenFromResult */, account.name,
3931                     false /* authDetailsRequired */) {
3932                 @Override
3933                 protected String toDebugString(long now) {
3934                     return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3935                             + ", " + account.toSafeString();
3936                 }
3937 
3938                 @Override
3939                 public void run() throws RemoteException {
3940                     mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3941                 }
3942 
3943                 @Override
3944                 public void onResult(Bundle result) {
3945                     Bundle.setDefusable(result, true);
3946                     IAccountManagerResponse response = getResponseAndClose();
3947                     if (response == null) {
3948                         return;
3949                     }
3950 
3951                     if (result == null) {
3952                         sendErrorResponse(
3953                                 response,
3954                                 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3955                                 "null bundle");
3956                         return;
3957                     }
3958 
3959                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
3960                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3961                                 + response);
3962                     }
3963                     // Check to see if an error occurred. We know if an error occurred because all
3964                     // error codes are greater than 0.
3965                     if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3966                         sendErrorResponse(response,
3967                                 result.getInt(AccountManager.KEY_ERROR_CODE),
3968                                 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3969                         return;
3970                     }
3971                     if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3972                         sendErrorResponse(
3973                                 response,
3974                                 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3975                                 "no result in response");
3976                         return;
3977                     }
3978                     final Bundle newResult = new Bundle();
3979                     newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3980                             result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3981                     sendResponse(response, newResult);
3982                 }
3983             }.bind();
3984         } finally {
3985             restoreCallingIdentity(identityToken);
3986         }
3987     }
3988 
3989     @Override
editProperties(IAccountManagerResponse response, final String accountType, final boolean expectActivityLaunch)3990     public void editProperties(IAccountManagerResponse response, final String accountType,
3991             final boolean expectActivityLaunch) {
3992         final int callingUid = Binder.getCallingUid();
3993         if (Log.isLoggable(TAG, Log.VERBOSE)) {
3994             Log.v(TAG, "editProperties: accountType " + accountType
3995                     + ", response " + response
3996                     + ", expectActivityLaunch " + expectActivityLaunch
3997                     + ", caller's uid " + callingUid
3998                     + ", pid " + Binder.getCallingPid());
3999         }
4000         if (response == null) throw new IllegalArgumentException("response is null");
4001         if (accountType == null) throw new IllegalArgumentException("accountType is null");
4002         int userId = UserHandle.getCallingUserId();
4003         if (!isAccountManagedByCaller(accountType, callingUid, userId)
4004                 && !isSystemUid(callingUid)) {
4005             String msg = String.format(
4006                     "uid %s cannot edit authenticator properites for account type: %s",
4007                     callingUid,
4008                     accountType);
4009             throw new SecurityException(msg);
4010         }
4011         final long identityToken = clearCallingIdentity();
4012         try {
4013             UserAccounts accounts = getUserAccounts(userId);
4014             new Session(accounts, response, accountType, expectActivityLaunch,
4015                     true /* stripAuthTokenFromResult */, null /* accountName */,
4016                     false /* authDetailsRequired */) {
4017                 @Override
4018                 public void run() throws RemoteException {
4019                     mAuthenticator.editProperties(this, mAccountType);
4020                 }
4021                 @Override
4022                 protected String toDebugString(long now) {
4023                     return super.toDebugString(now) + ", editProperties"
4024                             + ", accountType " + accountType;
4025                 }
4026             }.bind();
4027         } finally {
4028             restoreCallingIdentity(identityToken);
4029         }
4030     }
4031 
4032     @Override
hasAccountAccess(@onNull Account account, @NonNull String packageName, @NonNull UserHandle userHandle)4033     public boolean hasAccountAccess(@NonNull Account account,  @NonNull String packageName,
4034             @NonNull UserHandle userHandle) {
4035         if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
4036             throw new SecurityException("Can be called only by system UID");
4037         }
4038         Objects.requireNonNull(account, "account cannot be null");
4039         Objects.requireNonNull(packageName, "packageName cannot be null");
4040         Objects.requireNonNull(userHandle, "userHandle cannot be null");
4041 
4042         final int userId = userHandle.getIdentifier();
4043 
4044         Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
4045 
4046         try {
4047             int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
4048             return hasAccountAccess(account, packageName, uid);
4049         } catch (NameNotFoundException e) {
4050             Log.d(TAG, "Package not found " + e.getMessage());
4051             return false;
4052         }
4053     }
4054 
4055     // Returns package with oldest target SDK for given UID.
getPackageNameForUid(int uid)4056     private String getPackageNameForUid(int uid) {
4057         String[] packageNames = mPackageManager.getPackagesForUid(uid);
4058         if (ArrayUtils.isEmpty(packageNames)) {
4059             return null;
4060         }
4061         String packageName = packageNames[0];
4062         if (packageNames.length == 1) {
4063             return packageName;
4064         }
4065         // Due to visibility changes we want to use package with oldest target SDK
4066         int oldestVersion = Integer.MAX_VALUE;
4067         for (String name : packageNames) {
4068             try {
4069                 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
4070                 if (applicationInfo != null) {
4071                     int version = applicationInfo.targetSdkVersion;
4072                     if (version < oldestVersion) {
4073                         oldestVersion = version;
4074                         packageName = name;
4075                     }
4076                 }
4077             } catch (NameNotFoundException e) {
4078                 // skip
4079             }
4080         }
4081         return packageName;
4082     }
4083 
hasAccountAccess(@onNull Account account, @Nullable String packageName, int uid)4084     private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
4085             int uid) {
4086         if (packageName == null) {
4087             packageName = getPackageNameForUid(uid);
4088             if (packageName == null) {
4089                 return false;
4090             }
4091         }
4092 
4093         // Use null token which means any token. Having a token means the package
4094         // is trusted by the authenticator, hence it is fine to access the account.
4095         if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
4096             return true;
4097         }
4098         // In addition to the permissions required to get an auth token we also allow
4099         // the account to be accessed by apps for which user or authenticator granted visibility.
4100 
4101         int visibility = resolveAccountVisibility(account, packageName,
4102             getUserAccounts(UserHandle.getUserId(uid)));
4103         return (visibility == AccountManager.VISIBILITY_VISIBLE
4104             || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
4105     }
4106 
4107     @Override
createRequestAccountAccessIntentSenderAsUser(@onNull Account account, @NonNull String packageName, @NonNull UserHandle userHandle)4108     public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
4109             @NonNull String packageName, @NonNull UserHandle userHandle) {
4110         if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
4111             throw new SecurityException("Can be called only by system UID");
4112         }
4113 
4114         Objects.requireNonNull(account, "account cannot be null");
4115         Objects.requireNonNull(packageName, "packageName cannot be null");
4116         Objects.requireNonNull(userHandle, "userHandle cannot be null");
4117 
4118         final int userId = userHandle.getIdentifier();
4119 
4120         Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
4121 
4122         final int uid;
4123         try {
4124             uid = mPackageManager.getPackageUidAsUser(packageName, userId);
4125         } catch (NameNotFoundException e) {
4126             Slog.e(TAG, "Unknown package " + packageName);
4127             return null;
4128         }
4129 
4130         Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
4131 
4132         final long identity = Binder.clearCallingIdentity();
4133         try {
4134             return PendingIntent.getActivityAsUser(
4135                     mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
4136                             | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
4137                     null, new UserHandle(userId)).getIntentSender();
4138         } finally {
4139             Binder.restoreCallingIdentity(identity);
4140         }
4141     }
4142 
newRequestAccountAccessIntent(Account account, String packageName, int uid, RemoteCallback callback)4143     private Intent newRequestAccountAccessIntent(Account account, String packageName,
4144             int uid, RemoteCallback callback) {
4145         return newGrantCredentialsPermissionIntent(account, packageName, uid,
4146                 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
4147             @Override
4148             public void onResult(Bundle value) throws RemoteException {
4149                 handleAuthenticatorResponse(true);
4150             }
4151 
4152             @Override
4153             public void onRequestContinued() {
4154                 /* ignore */
4155             }
4156 
4157             @Override
4158             public void onError(int errorCode, String errorMessage) throws RemoteException {
4159                 handleAuthenticatorResponse(false);
4160             }
4161 
4162             private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4163                 cancelNotification(getCredentialPermissionNotificationId(account,
4164                         AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid),
4165                         UserHandle.getUserHandleForUid(uid));
4166                 if (callback != null) {
4167                     Bundle result = new Bundle();
4168                     result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4169                     callback.sendResult(result);
4170                 }
4171             }
4172         }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
4173     }
4174 
4175     @Override
4176     public boolean someUserHasAccount(@NonNull final Account account) {
4177         if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4178             throw new SecurityException("Only system can check for accounts across users");
4179         }
4180         final long token = Binder.clearCallingIdentity();
4181         try {
4182             AccountAndUser[] allAccounts = getAllAccounts();
4183             for (int i = allAccounts.length - 1; i >= 0; i--) {
4184                 if (allAccounts[i].account.equals(account)) {
4185                     return true;
4186                 }
4187             }
4188             return false;
4189         } finally {
4190             Binder.restoreCallingIdentity(token);
4191         }
4192     }
4193 
4194     private class GetAccountsByTypeAndFeatureSession extends Session {
4195         private final String[] mFeatures;
4196         private volatile Account[] mAccountsOfType = null;
4197         private volatile ArrayList<Account> mAccountsWithFeatures = null;
4198         private volatile int mCurrentAccount = 0;
4199         private final int mCallingUid;
4200         private final String mPackageName;
4201         private final boolean mIncludeManagedNotVisible;
4202 
4203         public GetAccountsByTypeAndFeatureSession(
4204                 UserAccounts accounts,
4205                 IAccountManagerResponse response,
4206                 String type,
4207                 String[] features,
4208                 int callingUid,
4209                 String packageName,
4210                 boolean includeManagedNotVisible) {
4211             super(accounts, response, type, false /* expectActivityLaunch */,
4212                     true /* stripAuthTokenFromResult */, null /* accountName */,
4213                     false /* authDetailsRequired */);
4214             mCallingUid = callingUid;
4215             mFeatures = features;
4216             mPackageName = packageName;
4217             mIncludeManagedNotVisible = includeManagedNotVisible;
4218         }
4219 
4220         @Override
4221         public void run() throws RemoteException {
4222             mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
4223                     mCallingUid, mPackageName, mIncludeManagedNotVisible);
4224             // check whether each account matches the requested features
4225             mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
4226             mCurrentAccount = 0;
4227 
4228             checkAccount();
4229         }
4230 
4231         public void checkAccount() {
4232             if (mCurrentAccount >= mAccountsOfType.length) {
4233                 sendResult();
4234                 return;
4235             }
4236 
4237             final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4238             if (accountAuthenticator == null) {
4239                 // It is possible that the authenticator has died, which is indicated by
4240                 // mAuthenticator being set to null. If this happens then just abort.
4241                 // There is no need to send back a result or error in this case since
4242                 // that already happened when mAuthenticator was cleared.
4243                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4244                     Log.v(TAG, "checkAccount: aborting session since we are no longer"
4245                             + " connected to the authenticator, " + toDebugString());
4246                 }
4247                 return;
4248             }
4249             try {
4250                 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
4251             } catch (RemoteException e) {
4252                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
4253             }
4254         }
4255 
4256         @Override
4257         public void onResult(Bundle result) {
4258             Bundle.setDefusable(result, true);
4259             mNumResults++;
4260             if (result == null) {
4261                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
4262                 return;
4263             }
4264             if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
4265                 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4266             }
4267             mCurrentAccount++;
4268             checkAccount();
4269         }
4270 
4271         public void sendResult() {
4272             IAccountManagerResponse response = getResponseAndClose();
4273             if (response != null) {
4274                 try {
4275                     Account[] accounts = new Account[mAccountsWithFeatures.size()];
4276                     for (int i = 0; i < accounts.length; i++) {
4277                         accounts[i] = mAccountsWithFeatures.get(i);
4278                     }
4279                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4280                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4281                                 + response);
4282                     }
4283                     Bundle result = new Bundle();
4284                     result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4285                     response.onResult(result);
4286                 } catch (RemoteException e) {
4287                     // if the caller is dead then there is no one to care about remote exceptions
4288                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4289                         Log.v(TAG, "failure while notifying response", e);
4290                     }
4291                 }
4292             }
4293         }
4294 
4295         @Override
4296         protected String toDebugString(long now) {
4297             return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4298                     + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4299         }
4300     }
4301 
4302     /**
4303      * Returns the accounts visible to the client within the context of a specific user
4304      * @hide
4305      */
4306     @NonNull
4307     public Account[] getAccounts(int userId, String opPackageName) {
4308         int callingUid = Binder.getCallingUid();
4309         mAppOpsManager.checkPackage(callingUid, opPackageName);
4310         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4311                 opPackageName);
4312         if (visibleAccountTypes.isEmpty()) {
4313             return EMPTY_ACCOUNT_ARRAY;
4314         }
4315         final long identityToken = clearCallingIdentity();
4316         try {
4317             UserAccounts accounts = getUserAccounts(userId);
4318             return getAccountsInternal(
4319                     accounts,
4320                     callingUid,
4321                     opPackageName,
4322                     visibleAccountTypes,
4323                     false /* includeUserManagedNotVisible */);
4324         } finally {
4325             restoreCallingIdentity(identityToken);
4326         }
4327     }
4328 
4329     /**
4330      * Returns accounts for all running users, ignores visibility values.
4331      *
4332      * @hide
4333      */
4334     @NonNull
4335     public AccountAndUser[] getRunningAccounts() {
4336         final int[] runningUserIds;
4337         try {
4338             runningUserIds = ActivityManager.getService().getRunningUserIds();
4339         } catch (RemoteException e) {
4340             // Running in system_server; should never happen
4341             throw new RuntimeException(e);
4342         }
4343         return getAccounts(runningUserIds);
4344     }
4345 
4346     /**
4347      * Returns accounts for all users, ignores visibility values.
4348      *
4349      * @hide
4350      */
4351     @NonNull
4352     public AccountAndUser[] getAllAccounts() {
4353         final List<UserInfo> users = getUserManager().getAliveUsers();
4354         final int[] userIds = new int[users.size()];
4355         for (int i = 0; i < userIds.length; i++) {
4356             userIds[i] = users.get(i).id;
4357         }
4358         return getAccounts(userIds);
4359     }
4360 
4361     @NonNull
4362     private AccountAndUser[] getAccounts(int[] userIds) {
4363         final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
4364         for (int userId : userIds) {
4365             UserAccounts userAccounts = getUserAccounts(userId);
4366             if (userAccounts == null) continue;
4367             Account[] accounts = getAccountsFromCache(
4368                     userAccounts,
4369                     null /* type */,
4370                     Binder.getCallingUid(),
4371                     null /* packageName */,
4372                     false /* include managed not visible*/);
4373             for (Account account : accounts) {
4374                 runningAccounts.add(new AccountAndUser(account, userId));
4375             }
4376         }
4377 
4378         AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4379         return runningAccounts.toArray(accountsArray);
4380     }
4381 
4382     @Override
4383     @NonNull
4384     public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
4385         int callingUid = Binder.getCallingUid();
4386         mAppOpsManager.checkPackage(callingUid, opPackageName);
4387         return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
4388                 opPackageName, false /* includeUserManagedNotVisible */);
4389     }
4390 
4391     @NonNull
4392     private Account[] getAccountsAsUserForPackage(
4393             String type,
4394             int userId,
4395             String callingPackage,
4396             int packageUid,
4397             String opPackageName,
4398             boolean includeUserManagedNotVisible) {
4399         int callingUid = Binder.getCallingUid();
4400         // Only allow the system process to read accounts of other users
4401         if (userId != UserHandle.getCallingUserId()
4402                 && callingUid != Process.SYSTEM_UID
4403                 && mContext.checkCallingOrSelfPermission(
4404                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4405                     != PackageManager.PERMISSION_GRANTED) {
4406             throw new SecurityException("User " + UserHandle.getCallingUserId()
4407                     + " trying to get account for " + userId);
4408         }
4409 
4410         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4411             Log.v(TAG, "getAccounts: accountType " + type
4412                     + ", caller's uid " + Binder.getCallingUid()
4413                     + ", pid " + Binder.getCallingPid());
4414         }
4415 
4416         // If the original calling app was using account choosing activity
4417         // provided by the framework or authenticator we'll passing in
4418         // the original caller's uid here, which is what should be used for filtering.
4419         List<String> managedTypes =
4420                 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4421         if (packageUid != -1 &&
4422                 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4423                 || (type != null && managedTypes.contains(type))))) {
4424             callingUid = packageUid;
4425             opPackageName = callingPackage;
4426         }
4427         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4428                 opPackageName);
4429         if (visibleAccountTypes.isEmpty()
4430                 || (type != null && !visibleAccountTypes.contains(type))) {
4431             return EMPTY_ACCOUNT_ARRAY;
4432         } else if (visibleAccountTypes.contains(type)) {
4433             // Prune the list down to just the requested type.
4434             visibleAccountTypes = new ArrayList<>();
4435             visibleAccountTypes.add(type);
4436         } // else aggregate all the visible accounts (it won't matter if the
4437           // list is empty).
4438 
4439         final long identityToken = clearCallingIdentity();
4440         try {
4441             UserAccounts accounts = getUserAccounts(userId);
4442             return getAccountsInternal(
4443                     accounts,
4444                     callingUid,
4445                     opPackageName,
4446                     visibleAccountTypes,
4447                     includeUserManagedNotVisible);
4448         } finally {
4449             restoreCallingIdentity(identityToken);
4450         }
4451     }
4452 
4453     @NonNull
4454     private Account[] getAccountsInternal(
4455             UserAccounts userAccounts,
4456             int callingUid,
4457             String callingPackage,
4458             List<String> visibleAccountTypes,
4459             boolean includeUserManagedNotVisible) {
4460         ArrayList<Account> visibleAccounts = new ArrayList<>();
4461         for (String visibleType : visibleAccountTypes) {
4462             Account[] accountsForType = getAccountsFromCache(
4463                     userAccounts, visibleType, callingUid, callingPackage,
4464                     includeUserManagedNotVisible);
4465             if (accountsForType != null) {
4466                 visibleAccounts.addAll(Arrays.asList(accountsForType));
4467             }
4468         }
4469         Account[] result = new Account[visibleAccounts.size()];
4470         for (int i = 0; i < visibleAccounts.size(); i++) {
4471             result[i] = visibleAccounts.get(i);
4472         }
4473         return result;
4474     }
4475 
4476     @Override
4477     public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4478             String opPackageName) {
4479         checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
4480         Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
4481         for (Account account : accounts) {
4482             addSharedAccountAsUser(account, userId);
4483         }
4484     }
4485 
4486     private boolean addSharedAccountAsUser(Account account, int userId) {
4487         userId = handleIncomingUser(userId);
4488         UserAccounts accounts = getUserAccounts(userId);
4489         accounts.accountsDb.deleteSharedAccount(account);
4490         long accountId = accounts.accountsDb.insertSharedAccount(account);
4491         if (accountId < 0) {
4492             Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
4493                     + ", skipping the DB insert failed");
4494             return false;
4495         }
4496         logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4497                 accounts);
4498         return true;
4499     }
4500 
4501     public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4502         userId = handleIncomingUser(userId);
4503         UserAccounts accounts = getUserAccounts(userId);
4504         long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4505         int r = accounts.accountsDb.renameSharedAccount(account, newName);
4506         if (r > 0) {
4507             int callingUid = getCallingUid();
4508             logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
4509                     sharedTableAccountId, accounts, callingUid);
4510             // Recursively rename the account.
4511             renameAccountInternal(accounts, account, newName);
4512         }
4513         return r > 0;
4514     }
4515 
4516     public boolean removeSharedAccountAsUser(Account account, int userId) {
4517         return removeSharedAccountAsUser(account, userId, getCallingUid());
4518     }
4519 
4520     private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
4521         userId = handleIncomingUser(userId);
4522         UserAccounts accounts = getUserAccounts(userId);
4523         long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4524         boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
4525         if (deleted) {
4526             logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
4527                     sharedTableAccountId, accounts, callingUid);
4528             removeAccountInternal(accounts, account, callingUid);
4529         }
4530         return deleted;
4531     }
4532 
4533     public Account[] getSharedAccountsAsUser(int userId) {
4534         userId = handleIncomingUser(userId);
4535         UserAccounts accounts = getUserAccounts(userId);
4536         synchronized (accounts.dbLock) {
4537             List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4538             Account[] accountArray = new Account[accountList.size()];
4539             accountList.toArray(accountArray);
4540             return accountArray;
4541         }
4542     }
4543 
4544     @Override
4545     @NonNull
4546     public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
4547         int callingUid = Binder.getCallingUid();
4548         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
4549             // Don't do opPackageName check - caller is system.
4550             throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4551                     + callingUid + " with uid=" + uid);
4552         }
4553         return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
4554                 opPackageName, true /* includeUserManagedNotVisible */);
4555     }
4556 
4557     @Override
4558     @NonNull
4559     public Account[] getAccountsByTypeForPackage(String type, String packageName,
4560             String opPackageName) {
4561         int callingUid =  Binder.getCallingUid();
4562         int userId = UserHandle.getCallingUserId();
4563         mAppOpsManager.checkPackage(callingUid, opPackageName);
4564         int packageUid = -1;
4565         try {
4566             packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4567         } catch (NameNotFoundException re) {
4568             Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
4569             return EMPTY_ACCOUNT_ARRAY;
4570         }
4571         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4572                 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4573                 return EMPTY_ACCOUNT_ARRAY;
4574         }
4575         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4576             return getAccountsAsUserForPackage(type, userId,
4577                 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4578         }
4579         return getAccountsAsUserForPackage(type, userId,
4580                 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
4581     }
4582 
4583     private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4584         if (accounts.length < 1) return false;
4585         if (accounts.length > 1) return true;
4586         Account account = accounts[0];
4587         UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4588         int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4589         if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4590         return false;
4591     }
4592 
4593     private void startChooseAccountActivityWithAccounts(
4594         IAccountManagerResponse response, Account[] accounts, String callingPackage) {
4595         Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4596         intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4597         intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4598                 new AccountManagerResponse(response));
4599         intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
4600 
4601         mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4602     }
4603 
4604     private void handleGetAccountsResult(
4605         IAccountManagerResponse response,
4606         Account[] accounts,
4607         String callingPackage) {
4608 
4609         if (needToStartChooseAccountActivity(accounts, callingPackage)) {
4610             startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
4611             return;
4612         }
4613         if (accounts.length == 1) {
4614             Bundle bundle = new Bundle();
4615             bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4616             bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4617             onResult(response, bundle);
4618             return;
4619         }
4620         // No qualified account exists, return an empty Bundle.
4621         onResult(response, new Bundle());
4622     }
4623 
4624     @Override
4625     public void getAccountByTypeAndFeatures(
4626         IAccountManagerResponse response,
4627         String accountType,
4628         String[] features,
4629         String opPackageName) {
4630 
4631         int callingUid = Binder.getCallingUid();
4632         mAppOpsManager.checkPackage(callingUid, opPackageName);
4633         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4634             Log.v(TAG, "getAccount: accountType " + accountType
4635                     + ", response " + response
4636                     + ", features " + Arrays.toString(features)
4637                     + ", caller's uid " + callingUid
4638                     + ", pid " + Binder.getCallingPid());
4639         }
4640         if (response == null) throw new IllegalArgumentException("response is null");
4641         if (accountType == null) throw new IllegalArgumentException("accountType is null");
4642 
4643         int userId = UserHandle.getCallingUserId();
4644 
4645         final long identityToken = clearCallingIdentity();
4646         try {
4647             UserAccounts userAccounts = getUserAccounts(userId);
4648             if (ArrayUtils.isEmpty(features)) {
4649                 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4650                     userAccounts, accountType, callingUid, opPackageName,
4651                     true /* include managed not visible */);
4652                 handleGetAccountsResult(
4653                     response, accountsWithManagedNotVisible, opPackageName);
4654                 return;
4655             }
4656 
4657             IAccountManagerResponse retrieveAccountsResponse =
4658                 new IAccountManagerResponse.Stub() {
4659                 @Override
4660                 public void onResult(Bundle value) throws RemoteException {
4661                     Parcelable[] parcelables = value.getParcelableArray(
4662                         AccountManager.KEY_ACCOUNTS);
4663                     Account[] accounts = new Account[parcelables.length];
4664                     for (int i = 0; i < parcelables.length; i++) {
4665                         accounts[i] = (Account) parcelables[i];
4666                     }
4667                     handleGetAccountsResult(
4668                         response, accounts, opPackageName);
4669                 }
4670 
4671                 @Override
4672                 public void onError(int errorCode, String errorMessage)
4673                         throws RemoteException {
4674                     // Will not be called in this case.
4675                 }
4676             };
4677             new GetAccountsByTypeAndFeatureSession(
4678                     userAccounts,
4679                     retrieveAccountsResponse,
4680                     accountType,
4681                     features,
4682                     callingUid,
4683                     opPackageName,
4684                     true /* include managed not visible */).bind();
4685         } finally {
4686             restoreCallingIdentity(identityToken);
4687         }
4688     }
4689 
4690     @Override
4691     public void getAccountsByFeatures(
4692             IAccountManagerResponse response,
4693             String type,
4694             String[] features,
4695             String opPackageName) {
4696         int callingUid = Binder.getCallingUid();
4697         mAppOpsManager.checkPackage(callingUid, opPackageName);
4698         if (Log.isLoggable(TAG, Log.VERBOSE)) {
4699             Log.v(TAG, "getAccounts: accountType " + type
4700                     + ", response " + response
4701                     + ", features " + Arrays.toString(features)
4702                     + ", caller's uid " + callingUid
4703                     + ", pid " + Binder.getCallingPid());
4704         }
4705         if (response == null) throw new IllegalArgumentException("response is null");
4706         if (type == null) throw new IllegalArgumentException("accountType is null");
4707         int userId = UserHandle.getCallingUserId();
4708 
4709         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4710                 opPackageName);
4711         if (!visibleAccountTypes.contains(type)) {
4712             Bundle result = new Bundle();
4713             // Need to return just the accounts that are from matching signatures.
4714             result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
4715             try {
4716                 response.onResult(result);
4717             } catch (RemoteException e) {
4718                 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4719             }
4720             return;
4721         }
4722 
4723         final long identityToken = clearCallingIdentity();
4724         try {
4725             UserAccounts userAccounts = getUserAccounts(userId);
4726             if (features == null || features.length == 0) {
4727                 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4728                         opPackageName, false);
4729                 Bundle result = new Bundle();
4730                 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4731                 onResult(response, result);
4732                 return;
4733             }
4734             new GetAccountsByTypeAndFeatureSession(
4735                     userAccounts,
4736                     response,
4737                     type,
4738                     features,
4739                     callingUid,
4740                     opPackageName,
4741                     false /* include managed not visible */).bind();
4742         } finally {
4743             restoreCallingIdentity(identityToken);
4744         }
4745     }
4746 
4747     @Override
4748     public void onAccountAccessed(String token) throws RemoteException {
4749         final int uid = Binder.getCallingUid();
4750         if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4751             return;
4752         }
4753         final int userId = UserHandle.getCallingUserId();
4754         final long identity = Binder.clearCallingIdentity();
4755         try {
4756             for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4757                 if (Objects.equals(account.getAccessId(), token)) {
4758                     // An app just accessed the account. At this point it knows about
4759                     // it and there is not need to hide this account from the app.
4760                     // Do we need to update account visibility here?
4761                     if (!hasAccountAccess(account, null, uid)) {
4762                         updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4763                                 uid, true);
4764                     }
4765                 }
4766             }
4767         } finally {
4768             Binder.restoreCallingIdentity(identity);
4769         }
4770     }
4771 
4772     @Override
4773     public void onShellCommand(FileDescriptor in, FileDescriptor out,
4774             FileDescriptor err, String[] args, ShellCallback callback,
4775             ResultReceiver resultReceiver) {
4776         new AccountManagerServiceShellCommand(this).exec(this, in, out, err, args,
4777                 callback, resultReceiver);
4778     }
4779 
4780     private abstract class Session extends IAccountAuthenticatorResponse.Stub
4781             implements IBinder.DeathRecipient, ServiceConnection {
4782         IAccountManagerResponse mResponse;
4783         final String mAccountType;
4784         final boolean mExpectActivityLaunch;
4785         final long mCreationTime;
4786         final String mAccountName;
4787         // Indicates if we need to add auth details(like last credential time)
4788         final boolean mAuthDetailsRequired;
4789         // If set, we need to update the last authenticated time. This is
4790         // currently
4791         // used on
4792         // successful confirming credentials.
4793         final boolean mUpdateLastAuthenticatedTime;
4794 
4795         public int mNumResults = 0;
4796         private int mNumRequestContinued = 0;
4797         private int mNumErrors = 0;
4798 
4799         IAccountAuthenticator mAuthenticator = null;
4800 
4801         private final boolean mStripAuthTokenFromResult;
4802         protected final UserAccounts mAccounts;
4803 
4804         public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4805                 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4806                 boolean authDetailsRequired) {
4807             this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4808                     accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4809         }
4810 
4811         public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4812                 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4813                 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
4814             super();
4815             //if (response == null) throw new IllegalArgumentException("response is null");
4816             if (accountType == null) throw new IllegalArgumentException("accountType is null");
4817             mAccounts = accounts;
4818             mStripAuthTokenFromResult = stripAuthTokenFromResult;
4819             mResponse = response;
4820             mAccountType = accountType;
4821             mExpectActivityLaunch = expectActivityLaunch;
4822             mCreationTime = SystemClock.elapsedRealtime();
4823             mAccountName = accountName;
4824             mAuthDetailsRequired = authDetailsRequired;
4825             mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
4826 
4827             synchronized (mSessions) {
4828                 mSessions.put(toString(), this);
4829             }
4830             if (response != null) {
4831                 try {
4832                     response.asBinder().linkToDeath(this, 0 /* flags */);
4833                 } catch (RemoteException e) {
4834                     mResponse = null;
4835                     binderDied();
4836                 }
4837             }
4838         }
4839 
4840         IAccountManagerResponse getResponseAndClose() {
4841             if (mResponse == null) {
4842                 close();
4843                 return null;
4844             }
4845             IAccountManagerResponse response = mResponse;
4846             close(); // this clears mResponse so we need to save the response before this call
4847             return response;
4848         }
4849 
4850         /**
4851          * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4852          * security policy.
4853          *
4854          * In particular we want to make sure that the Authenticator doesn't try to trick users
4855          * into launching arbitrary intents on the device via by tricking to click authenticator
4856          * supplied entries in the system Settings app.
4857          */
4858          protected boolean checkKeyIntent(int authUid, Intent intent) {
4859             // Explicitly set an empty ClipData to ensure that we don't offer to
4860             // promote any Uris contained inside for granting purposes
4861             if (intent.getClipData() == null) {
4862                 intent.setClipData(ClipData.newPlainText(null, null));
4863             }
4864             intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4865                     | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4866                     | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4867                     | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
4868             final long bid = Binder.clearCallingIdentity();
4869             try {
4870                 PackageManager pm = mContext.getPackageManager();
4871                 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4872                 if (resolveInfo == null) {
4873                     return false;
4874                 }
4875                 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4876                 int targetUid = targetActivityInfo.applicationInfo.uid;
4877                 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
4878                 if (!isExportedSystemActivity(targetActivityInfo)
4879                         && !pmi.hasSignatureCapability(
4880                                 targetUid, authUid,
4881                                 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
4882                     String pkgName = targetActivityInfo.packageName;
4883                     String activityName = targetActivityInfo.name;
4884                     String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4885                             + "does not share a signature with the supplying authenticator (%s).";
4886                     Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
4887                     return false;
4888                 }
4889                 return true;
4890             } finally {
4891                 Binder.restoreCallingIdentity(bid);
4892             }
4893         }
4894 
4895         private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4896             String className = activityInfo.name;
4897             return "android".equals(activityInfo.packageName) &&
4898                     (GrantCredentialsPermissionActivity.class.getName().equals(className)
4899                     || CantAddAccountActivity.class.getName().equals(className));
4900         }
4901 
4902         private void close() {
4903             synchronized (mSessions) {
4904                 if (mSessions.remove(toString()) == null) {
4905                     // the session was already closed, so bail out now
4906                     return;
4907                 }
4908             }
4909             if (mResponse != null) {
4910                 // stop listening for response deaths
4911                 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4912 
4913                 // clear this so that we don't accidentally send any further results
4914                 mResponse = null;
4915             }
4916             cancelTimeout();
4917             unbind();
4918         }
4919 
4920         @Override
4921         public void binderDied() {
4922             mResponse = null;
4923             close();
4924         }
4925 
4926         protected String toDebugString() {
4927             return toDebugString(SystemClock.elapsedRealtime());
4928         }
4929 
4930         protected String toDebugString(long now) {
4931             return "Session: expectLaunch " + mExpectActivityLaunch
4932                     + ", connected " + (mAuthenticator != null)
4933                     + ", stats (" + mNumResults + "/" + mNumRequestContinued
4934                     + "/" + mNumErrors + ")"
4935                     + ", lifetime " + ((now - mCreationTime) / 1000.0);
4936         }
4937 
4938         void bind() {
4939             if (Log.isLoggable(TAG, Log.VERBOSE)) {
4940                 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4941             }
4942             if (!bindToAuthenticator(mAccountType)) {
4943                 Log.d(TAG, "bind attempt failed for " + toDebugString());
4944                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
4945             }
4946         }
4947 
4948         private void unbind() {
4949             if (mAuthenticator != null) {
4950                 mAuthenticator = null;
4951                 mContext.unbindService(this);
4952             }
4953         }
4954 
4955         public void cancelTimeout() {
4956             mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
4957         }
4958 
4959         @Override
4960         public void onServiceConnected(ComponentName name, IBinder service) {
4961             mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
4962             try {
4963                 run();
4964             } catch (RemoteException e) {
4965                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4966                         "remote exception");
4967             }
4968         }
4969 
4970         @Override
4971         public void onServiceDisconnected(ComponentName name) {
4972             mAuthenticator = null;
4973             IAccountManagerResponse response = getResponseAndClose();
4974             if (response != null) {
4975                 try {
4976                     response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4977                             "disconnected");
4978                 } catch (RemoteException e) {
4979                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4980                         Log.v(TAG, "Session.onServiceDisconnected: "
4981                                 + "caught RemoteException while responding", e);
4982                     }
4983                 }
4984             }
4985         }
4986 
4987         public abstract void run() throws RemoteException;
4988 
4989         public void onTimedOut() {
4990             IAccountManagerResponse response = getResponseAndClose();
4991             if (response != null) {
4992                 try {
4993                     response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4994                             "timeout");
4995                 } catch (RemoteException e) {
4996                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
4997                         Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4998                                 e);
4999                     }
5000                 }
5001             }
5002         }
5003 
5004         @Override
5005         public void onResult(Bundle result) {
5006             Bundle.setDefusable(result, true);
5007             mNumResults++;
5008             Intent intent = null;
5009             if (result != null) {
5010                 boolean isSuccessfulConfirmCreds = result.getBoolean(
5011                         AccountManager.KEY_BOOLEAN_RESULT, false);
5012                 boolean isSuccessfulUpdateCredsOrAddAccount =
5013                         result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
5014                         && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
5015                 // We should only update lastAuthenticated time, if
5016                 // mUpdateLastAuthenticatedTime is true and the confirmRequest
5017                 // or updateRequest was successful
5018                 boolean needUpdate = mUpdateLastAuthenticatedTime
5019                         && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
5020                 if (needUpdate || mAuthDetailsRequired) {
5021                     boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
5022                     if (needUpdate && accountPresent) {
5023                         updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
5024                     }
5025                     if (mAuthDetailsRequired) {
5026                         long lastAuthenticatedTime = -1;
5027                         if (accountPresent) {
5028                             lastAuthenticatedTime = mAccounts.accountsDb
5029                                     .findAccountLastAuthenticatedTime(
5030                                             new Account(mAccountName, mAccountType));
5031                         }
5032                         result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
5033                                 lastAuthenticatedTime);
5034                     }
5035                 }
5036             }
5037             if (result != null
5038                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
5039                 if (!checkKeyIntent(
5040                         Binder.getCallingUid(),
5041                         intent)) {
5042                     onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
5043                             "invalid intent in bundle returned");
5044                     return;
5045                 }
5046             }
5047             if (result != null
5048                     && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
5049                 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
5050                 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
5051                 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
5052                     Account account = new Account(accountName, accountType);
5053                     cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
5054                             new UserHandle(mAccounts.userId));
5055                 }
5056             }
5057             IAccountManagerResponse response;
5058             if (mExpectActivityLaunch && result != null
5059                     && result.containsKey(AccountManager.KEY_INTENT)) {
5060                 response = mResponse;
5061             } else {
5062                 response = getResponseAndClose();
5063             }
5064             if (response != null) {
5065                 try {
5066                     if (result == null) {
5067                         if (Log.isLoggable(TAG, Log.VERBOSE)) {
5068                             Log.v(TAG, getClass().getSimpleName()
5069                                     + " calling onError() on response " + response);
5070                         }
5071                         response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
5072                                 "null bundle returned");
5073                     } else {
5074                         if (mStripAuthTokenFromResult) {
5075                             result.remove(AccountManager.KEY_AUTHTOKEN);
5076                         }
5077                         if (Log.isLoggable(TAG, Log.VERBOSE)) {
5078                             Log.v(TAG, getClass().getSimpleName()
5079                                     + " calling onResult() on response " + response);
5080                         }
5081                         if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
5082                                 (intent == null)) {
5083                             // All AccountManager error codes are greater than 0
5084                             response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
5085                                     result.getString(AccountManager.KEY_ERROR_MESSAGE));
5086                         } else {
5087                             response.onResult(result);
5088                         }
5089                     }
5090                 } catch (RemoteException e) {
5091                     // if the caller is dead then there is no one to care about remote exceptions
5092                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
5093                         Log.v(TAG, "failure while notifying response", e);
5094                     }
5095                 }
5096             }
5097         }
5098 
5099         @Override
5100         public void onRequestContinued() {
5101             mNumRequestContinued++;
5102         }
5103 
5104         @Override
5105         public void onError(int errorCode, String errorMessage) {
5106             mNumErrors++;
5107             IAccountManagerResponse response = getResponseAndClose();
5108             if (response != null) {
5109                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5110                     Log.v(TAG, getClass().getSimpleName()
5111                             + " calling onError() on response " + response);
5112                 }
5113                 try {
5114                     response.onError(errorCode, errorMessage);
5115                 } catch (RemoteException e) {
5116                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
5117                         Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
5118                     }
5119                 }
5120             } else {
5121                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5122                     Log.v(TAG, "Session.onError: already closed");
5123                 }
5124             }
5125         }
5126 
5127         /**
5128          * find the component name for the authenticator and initiate a bind
5129          * if no authenticator or the bind fails then return false, otherwise return true
5130          */
5131         private boolean bindToAuthenticator(String authenticatorType) {
5132             final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
5133             authenticatorInfo = mAuthenticatorCache.getServiceInfo(
5134                     AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
5135             if (authenticatorInfo == null) {
5136                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5137                     Log.v(TAG, "there is no authenticator for " + authenticatorType
5138                             + ", bailing out");
5139                 }
5140                 return false;
5141             }
5142 
5143             if (!isLocalUnlockedUser(mAccounts.userId)
5144                     && !authenticatorInfo.componentInfo.directBootAware) {
5145                 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
5146                         + " which isn't encryption aware");
5147                 return false;
5148             }
5149 
5150             Intent intent = new Intent();
5151             intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
5152             intent.setComponent(authenticatorInfo.componentName);
5153             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5154                 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
5155             }
5156             int flags = Context.BIND_AUTO_CREATE;
5157             if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
5158                 flags |= Context.BIND_ALLOW_INSTANT;
5159             }
5160             if (!mContext.bindServiceAsUser(intent, this, flags, UserHandle.of(mAccounts.userId))) {
5161                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5162                     Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
5163                 }
5164                 return false;
5165             }
5166 
5167             return true;
5168         }
5169     }
5170 
5171     class MessageHandler extends Handler {
5172         MessageHandler(Looper looper) {
5173             super(looper);
5174         }
5175 
5176         @Override
5177         public void handleMessage(Message msg) {
5178             switch (msg.what) {
5179                 case MESSAGE_TIMED_OUT:
5180                     Session session = (Session)msg.obj;
5181                     session.onTimedOut();
5182                     break;
5183 
5184                 case MESSAGE_COPY_SHARED_ACCOUNT:
5185                     copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
5186                     break;
5187 
5188                 default:
5189                     throw new IllegalStateException("unhandled message: " + msg.what);
5190             }
5191         }
5192     }
5193 
5194     private void logRecord(UserAccounts accounts, String action, String tableName) {
5195         logRecord(action, tableName, -1, accounts);
5196     }
5197 
5198     private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
5199         logRecord(action, tableName, -1, accounts, uid);
5200     }
5201 
5202     /*
5203      * This function receives an opened writable database.
5204      */
5205     private void logRecord(String action, String tableName, long accountId,
5206             UserAccounts userAccount) {
5207         logRecord(action, tableName, accountId, userAccount, getCallingUid());
5208     }
5209 
5210     /*
5211      * This function receives an opened writable database and writes to it in a separate thread.
5212      */
5213     private void logRecord(String action, String tableName, long accountId,
5214             UserAccounts userAccount, int callingUid) {
5215 
5216         class LogRecordTask implements Runnable {
5217             private final String action;
5218             private final String tableName;
5219             private final long accountId;
5220             private final UserAccounts userAccount;
5221             private final int callingUid;
5222             private final long userDebugDbInsertionPoint;
5223 
5224             LogRecordTask(final String action,
5225                     final String tableName,
5226                     final long accountId,
5227                     final UserAccounts userAccount,
5228                     final int callingUid,
5229                     final long userDebugDbInsertionPoint) {
5230                 this.action = action;
5231                 this.tableName = tableName;
5232                 this.accountId = accountId;
5233                 this.userAccount = userAccount;
5234                 this.callingUid = callingUid;
5235                 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5236             }
5237 
5238             @Override
5239             public void run() {
5240                 synchronized (userAccount.accountsDb.mDebugStatementLock) {
5241                     SQLiteStatement logStatement = userAccount.accountsDb.getStatementForLogging();
5242                     if (logStatement == null) {
5243                         return; // Can't log.
5244                     }
5245                     logStatement.bindLong(1, accountId);
5246                     logStatement.bindString(2, action);
5247                     logStatement.bindString(3, mDateFormat.format(new Date()));
5248                     logStatement.bindLong(4, callingUid);
5249                     logStatement.bindString(5, tableName);
5250                     logStatement.bindLong(6, userDebugDbInsertionPoint);
5251                     try {
5252                         logStatement.execute();
5253                     } catch (IllegalStateException e) {
5254                         // Guard against crash, DB can already be closed
5255                         // since this statement is executed on a handler thread
5256                         Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
5257                                 + " action=" + action + " tableName=" + tableName + " Error: " + e);
5258                     } finally {
5259                         logStatement.clearBindings();
5260                     }
5261                 }
5262             }
5263         }
5264         long insertionPoint = userAccount.accountsDb.reserveDebugDbInsertionPoint();
5265         if (insertionPoint != -1) {
5266             LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5267                     callingUid, insertionPoint);
5268             mHandler.post(logTask);
5269         }
5270     }
5271 
5272     public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
5273         return asBinder();
5274     }
5275 
5276     /**
5277      * Searches array of arguments for the specified string
5278      * @param args array of argument strings
5279      * @param value value to search for
5280      * @return true if the value is contained in the array
5281      */
5282     private static boolean scanArgs(String[] args, String value) {
5283         if (args != null) {
5284             for (String arg : args) {
5285                 if (value.equals(arg)) {
5286                     return true;
5287                 }
5288             }
5289         }
5290         return false;
5291     }
5292 
5293     @Override
5294     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
5295         if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
5296         final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
5297         final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, "  ");
5298 
5299         final List<UserInfo> users = getUserManager().getUsers();
5300         for (UserInfo user : users) {
5301             ipw.println("User " + user + ":");
5302             ipw.increaseIndent();
5303             dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5304             ipw.println();
5305             ipw.decreaseIndent();
5306         }
5307     }
5308 
5309     private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5310             String[] args, boolean isCheckinRequest) {
5311         if (isCheckinRequest) {
5312             // This is a checkin request. *Only* upload the account types and the count of
5313             // each.
5314             synchronized (userAccounts.dbLock) {
5315                 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5316             }
5317         } else {
5318             Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5319                     Process.SYSTEM_UID, null /* packageName */, false);
5320             fout.println("Accounts: " + accounts.length);
5321             for (Account account : accounts) {
5322                 fout.println("  " + account.toString());
5323             }
5324 
5325             // Add debug information.
5326             fout.println();
5327             synchronized (userAccounts.dbLock) {
5328                 userAccounts.accountsDb.dumpDebugTable(fout);
5329             }
5330             fout.println();
5331             synchronized (mSessions) {
5332                 final long now = SystemClock.elapsedRealtime();
5333                 fout.println("Active Sessions: " + mSessions.size());
5334                 for (Session session : mSessions.values()) {
5335                     fout.println("  " + session.toDebugString(now));
5336                 }
5337             }
5338 
5339             fout.println();
5340             mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
5341 
5342             boolean isUserUnlocked;
5343             synchronized (mUsers) {
5344                 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
5345             }
5346             // Following logs are printed only when user is unlocked.
5347             if (!isUserUnlocked) {
5348                 return;
5349             }
5350             fout.println();
5351             synchronized (userAccounts.dbLock) {
5352                 Map<Account, Map<String, Integer>> allVisibilityValues =
5353                         userAccounts.accountsDb.findAllVisibilityValues();
5354                 fout.println("Account visibility:");
5355                 for (Account account : allVisibilityValues.keySet()) {
5356                     fout.println("  " + account.name);
5357                     Map<String, Integer> visibilities = allVisibilityValues.get(account);
5358                     for (Entry<String, Integer> entry : visibilities.entrySet()) {
5359                         fout.println("    " + entry.getKey() + ", " + entry.getValue());
5360                     }
5361                 }
5362             }
5363         }
5364     }
5365 
5366     private void doNotification(UserAccounts accounts, Account account, CharSequence message,
5367             Intent intent, String packageName, final int userId) {
5368         final long identityToken = clearCallingIdentity();
5369         try {
5370             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5371                 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5372             }
5373 
5374             if (intent.getComponent() != null &&
5375                     GrantCredentialsPermissionActivity.class.getName().equals(
5376                             intent.getComponent().getClassName())) {
5377                 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
5378             } else {
5379                 Context contextForUser = getContextForUser(new UserHandle(userId));
5380                 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5381                 intent.addCategory(id.mTag);
5382 
5383                 final String notificationTitleFormat =
5384                         contextForUser.getText(R.string.notification_title).toString();
5385                 Notification n =
5386                         new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
5387                         .setWhen(0)
5388                         .setSmallIcon(android.R.drawable.stat_sys_warning)
5389                         .setColor(contextForUser.getColor(
5390                                 com.android.internal.R.color.system_notification_accent_color))
5391                         .setContentTitle(String.format(notificationTitleFormat, account.name))
5392                         .setContentText(message)
5393                         .setContentIntent(PendingIntent.getActivityAsUser(
5394                                 mContext, 0, intent,
5395                                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
5396                                 null, new UserHandle(userId)))
5397                         .build();
5398                 installNotification(id, n, packageName, userId);
5399             }
5400         } finally {
5401             restoreCallingIdentity(identityToken);
5402         }
5403     }
5404 
5405     private void installNotification(NotificationId id, final Notification notification,
5406             String packageName, int userId) {
5407         final long token = clearCallingIdentity();
5408         try {
5409             INotificationManager notificationManager = mInjector.getNotificationManager();
5410             try {
5411                 // The calling uid must match either the package or op package, so use an op
5412                 // package that matches the cleared calling identity.
5413                 notificationManager.enqueueNotificationWithTag(packageName, "android",
5414                         id.mTag, id.mId, notification, userId);
5415             } catch (RemoteException e) {
5416                 /* ignore - local call */
5417             }
5418         } finally {
5419             Binder.restoreCallingIdentity(token);
5420         }
5421     }
5422 
5423     private void cancelNotification(NotificationId id, UserHandle user) {
5424         cancelNotification(id, mContext.getPackageName(), user);
5425     }
5426 
5427     private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
5428         final long identityToken = clearCallingIdentity();
5429         try {
5430             INotificationManager service = mInjector.getNotificationManager();
5431             service.cancelNotificationWithTag(
5432                     packageName, "android", id.mTag, id.mId, user.getIdentifier());
5433         } catch (RemoteException e) {
5434             /* ignore - local call */
5435         } finally {
5436             restoreCallingIdentity(identityToken);
5437         }
5438     }
5439 
5440     private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
5441         final long identity = Binder.clearCallingIdentity();
5442         try {
5443             final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5444             IPackageManager pm = ActivityThread.getPackageManager();
5445             for (String perm : permissions) {
5446                 if (pm.checkPermission(perm, packageName, userId)
5447                         == PackageManager.PERMISSION_GRANTED) {
5448                     // Checks runtime permission revocation.
5449                     final int opCode = AppOpsManager.permissionToOpCode(perm);
5450                     if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.checkOpNoThrow(
5451                             opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5452                         return true;
5453                     }
5454                 }
5455             }
5456         } catch (NameNotFoundException | RemoteException e) {
5457             // Assume permission is not granted if an error accrued.
5458         } finally {
5459             Binder.restoreCallingIdentity(identity);
5460         }
5461         return false;
5462     }
5463 
5464     /**
5465      * Checks that package has at least one of given permissions and makes note of app
5466      * performing the action.
5467      */
5468     private boolean checkPermissionAndNote(String opPackageName, int callingUid,
5469             String... permissions) {
5470         for (String perm : permissions) {
5471             if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5472                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5473                     Log.v(TAG, "  caller uid " + callingUid + " has " + perm);
5474                 }
5475                 final int opCode = AppOpsManager.permissionToOpCode(perm);
5476                 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
5477                         opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5478                     return true;
5479                 }
5480             }
5481         }
5482         return false;
5483     }
5484 
5485     private int handleIncomingUser(int userId) {
5486         try {
5487             return ActivityManager.getService().handleIncomingUser(
5488                     Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5489         } catch (RemoteException re) {
5490             // Shouldn't happen, local.
5491         }
5492         return userId;
5493     }
5494 
5495     private boolean isPrivileged(int callingUid) {
5496         String[] packages;
5497         final long identityToken = Binder.clearCallingIdentity();
5498         try {
5499             packages = mPackageManager.getPackagesForUid(callingUid);
5500             if (packages == null) {
5501                 Log.d(TAG, "No packages for callingUid " + callingUid);
5502                 return false;
5503             }
5504             for (String name : packages) {
5505                 try {
5506                     PackageInfo packageInfo =
5507                         mPackageManager.getPackageInfo(name, 0 /* flags */);
5508                     if (packageInfo != null
5509                         && (packageInfo.applicationInfo.privateFlags
5510                             & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
5511                         return true;
5512                     }
5513                 } catch (PackageManager.NameNotFoundException e) {
5514                     Log.d(TAG, "Package not found " + e.getMessage());
5515                 }
5516             }
5517         } finally {
5518             Binder.restoreCallingIdentity(identityToken);
5519         }
5520         return false;
5521     }
5522 
5523     private boolean permissionIsGranted(
5524             Account account, String authTokenType, int callerUid, int userId) {
5525         if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5526             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5527                 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5528             }
5529             return true;
5530         }
5531 
5532         if (isPrivileged(callerUid)) {
5533             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5534                 Log.v(TAG, "Access to " + account + " granted calling uid "
5535                         + callerUid + " privileged");
5536             }
5537             return true;
5538         }
5539         if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5540             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5541                 Log.v(TAG, "Access to " + account + " granted calling uid "
5542                         + callerUid + " manages the account");
5543             }
5544             return true;
5545         }
5546         if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5547             if (Log.isLoggable(TAG, Log.VERBOSE)) {
5548                 Log.v(TAG, "Access to " + account + " granted calling uid "
5549                         + callerUid + " user granted access");
5550             }
5551             return true;
5552         }
5553 
5554         if (Log.isLoggable(TAG, Log.VERBOSE)) {
5555             Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5556         }
5557 
5558         return false;
5559     }
5560 
5561     private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5562             String opPackageName) {
5563         if (accountType == null) {
5564             return false;
5565         } else {
5566             return getTypesVisibleToCaller(callingUid, userId,
5567                     opPackageName).contains(accountType);
5568         }
5569     }
5570 
5571     // Method checks visibility for applications targeing API level below {@link
5572     // android.os.Build.VERSION_CODES#O},
5573     // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
5574     private boolean checkGetAccountsPermission(String packageName, int userId) {
5575         return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5576                 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5577     }
5578 
5579     private boolean checkReadContactsPermission(String packageName, int userId) {
5580         return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5581     }
5582 
5583     // Heuristic to check that account type may be associated with some contacts data and
5584     // therefore READ_CONTACTS permission grants the access to account by default.
5585     private boolean accountTypeManagesContacts(String accountType, int userId) {
5586         if (accountType == null) {
5587             return false;
5588         }
5589         final long identityToken = Binder.clearCallingIdentity();
5590         Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5591         try {
5592             serviceInfos = mAuthenticatorCache.getAllServices(userId);
5593         } finally {
5594             Binder.restoreCallingIdentity(identityToken);
5595         }
5596         // Check contacts related permissions for authenticator.
5597         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5598                 : serviceInfos) {
5599             if (accountType.equals(serviceInfo.type.type)) {
5600                 return isPermittedForPackage(serviceInfo.type.packageName, userId,
5601                     Manifest.permission.WRITE_CONTACTS);
5602             }
5603         }
5604         return false;
5605     }
5606 
5607     /**
5608      * Method checks package uid and signature with Authenticator which manages accountType.
5609      *
5610      * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5611      *         SIGNATURE_CHECK_MISMATCH otherwise.
5612      */
5613     private int checkPackageSignature(String accountType, int callingUid, int userId) {
5614         if (accountType == null) {
5615             return SIGNATURE_CHECK_MISMATCH;
5616         }
5617 
5618         final long identityToken = Binder.clearCallingIdentity();
5619         Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5620         try {
5621             serviceInfos = mAuthenticatorCache.getAllServices(userId);
5622         } finally {
5623             Binder.restoreCallingIdentity(identityToken);
5624         }
5625         // Check for signature match with Authenticator.LocalServices.getService(PackageManagerInternal.class);
5626         PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
5627         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5628                 : serviceInfos) {
5629             if (accountType.equals(serviceInfo.type.type)) {
5630                 if (serviceInfo.uid == callingUid) {
5631                     return SIGNATURE_CHECK_UID_MATCH;
5632                 }
5633                 if (pmi.hasSignatureCapability(
5634                         serviceInfo.uid, callingUid,
5635                         PackageParser.SigningDetails.CertCapabilities.AUTH)) {
5636                     return SIGNATURE_CHECK_MATCH;
5637                 }
5638             }
5639         }
5640         return SIGNATURE_CHECK_MISMATCH;
5641     }
5642 
5643     // returns true for applications with the same signature as authenticator.
5644     private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5645         if (accountType == null) {
5646             return false;
5647         } else {
5648             return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5649         }
5650     }
5651 
5652     private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5653             String opPackageName) {
5654         return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
5655     }
5656 
5657     private List<String> getTypesManagedByCaller(int callingUid, int userId) {
5658         return getTypesForCaller(callingUid, userId, false);
5659     }
5660 
5661     private List<String> getTypesForCaller(
5662             int callingUid, int userId, boolean isOtherwisePermitted) {
5663         List<String> managedAccountTypes = new ArrayList<>();
5664         final long identityToken = Binder.clearCallingIdentity();
5665         Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5666         try {
5667             serviceInfos = mAuthenticatorCache.getAllServices(userId);
5668         } finally {
5669             Binder.restoreCallingIdentity(identityToken);
5670         }
5671 
5672         PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
5673         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
5674                 serviceInfos) {
5675             if (isOtherwisePermitted || pmi.hasSignatureCapability(
5676                     serviceInfo.uid, callingUid,
5677                     PackageParser.SigningDetails.CertCapabilities.AUTH)) {
5678                 managedAccountTypes.add(serviceInfo.type.type);
5679             }
5680         }
5681         return managedAccountTypes;
5682     }
5683 
5684     private boolean isAccountPresentForCaller(String accountName, String accountType) {
5685         if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5686             for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5687                 if (account.name.equals(accountName)) {
5688                     return true;
5689                 }
5690             }
5691         }
5692         return false;
5693     }
5694 
5695     private static void checkManageUsersPermission(String message) {
5696         if (ActivityManager.checkComponentPermission(
5697                 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5698                 != PackageManager.PERMISSION_GRANTED) {
5699             throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5700         }
5701     }
5702 
5703     private static void checkManageOrCreateUsersPermission(String message) {
5704         if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5705                 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5706                 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5707                         Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5708             throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5709                     + message);
5710         }
5711     }
5712 
5713     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5714             int callerUid) {
5715         if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5716             return true;
5717         }
5718         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
5719         synchronized (accounts.dbLock) {
5720             synchronized (accounts.cacheLock) {
5721                 long grantsCount;
5722                 if (authTokenType != null) {
5723                     grantsCount = accounts.accountsDb
5724                             .findMatchingGrantsCount(callerUid, authTokenType, account);
5725                 } else {
5726                     grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5727                             account);
5728                 }
5729                 final boolean permissionGranted = grantsCount > 0;
5730 
5731                 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5732                     // TODO: Skip this check when running automated tests. Replace this
5733                     // with a more general solution.
5734                     Log.d(TAG, "no credentials permission for usage of "
5735                             + account.toSafeString() + ", "
5736                             + authTokenType + " by uid " + callerUid
5737                             + " but ignoring since device is in test harness.");
5738                     return true;
5739                 }
5740                 return permissionGranted;
5741             }
5742         }
5743     }
5744 
5745     private boolean isSystemUid(int callingUid) {
5746         String[] packages = null;
5747         final long ident = Binder.clearCallingIdentity();
5748         try {
5749             packages = mPackageManager.getPackagesForUid(callingUid);
5750             if (packages != null) {
5751                 for (String name : packages) {
5752                     try {
5753                         PackageInfo packageInfo =
5754                                 mPackageManager.getPackageInfo(name, 0 /* flags */);
5755                         if (packageInfo != null
5756                                 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5757                                 != 0) {
5758                             return true;
5759                         }
5760                     } catch (NameNotFoundException e) {
5761                         Log.w(TAG, String.format("Could not find package [%s]", name), e);
5762                     }
5763                 }
5764             } else {
5765                 Log.w(TAG, "No known packages with uid " + callingUid);
5766             }
5767         } finally {
5768             Binder.restoreCallingIdentity(ident);
5769         }
5770         return false;
5771     }
5772 
5773     /** Succeeds if any of the specified permissions are granted. */
5774     private void checkReadAccountsPermitted(
5775             int callingUid,
5776             String accountType,
5777             int userId,
5778             String opPackageName) {
5779         if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
5780             String msg = String.format(
5781                     "caller uid %s cannot access %s accounts",
5782                     callingUid,
5783                     accountType);
5784             Log.w(TAG, "  " + msg);
5785             throw new SecurityException(msg);
5786         }
5787     }
5788 
5789     private boolean canUserModifyAccounts(int userId, int callingUid) {
5790         // the managing app can always modify accounts
5791         if (isProfileOwner(callingUid)) {
5792             return true;
5793         }
5794         if (getUserManager().getUserRestrictions(new UserHandle(userId))
5795                 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5796             return false;
5797         }
5798         return true;
5799     }
5800 
5801     private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5802         // the managing app can always modify accounts
5803         if (isProfileOwner(callingUid)) {
5804             return true;
5805         }
5806         DevicePolicyManager dpm = (DevicePolicyManager) mContext
5807                 .getSystemService(Context.DEVICE_POLICY_SERVICE);
5808         String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
5809         if (typesArray == null) {
5810             return true;
5811         }
5812         for (String forbiddenType : typesArray) {
5813             if (forbiddenType.equals(accountType)) {
5814                 return false;
5815             }
5816         }
5817         return true;
5818     }
5819 
5820     private boolean isProfileOwner(int uid) {
5821         final DevicePolicyManagerInternal dpmi =
5822                 LocalServices.getService(DevicePolicyManagerInternal.class);
5823         //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
5824         return (dpmi != null) && (dpmi.isActiveProfileOwner(uid) || dpmi.isActiveDeviceOwner(uid));
5825     }
5826 
5827     @Override
5828     public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5829             throws RemoteException {
5830         final int callingUid = getCallingUid();
5831 
5832         if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
5833             throw new SecurityException();
5834         }
5835 
5836         if (value) {
5837             grantAppPermission(account, authTokenType, uid);
5838         } else {
5839             revokeAppPermission(account, authTokenType, uid);
5840         }
5841     }
5842 
5843     /**
5844      * Allow callers with the given uid permission to get credentials for account/authTokenType.
5845      * <p>
5846      * Although this is public it can only be accessed via the AccountManagerService object
5847      * which is in the system. This means we don't need to protect it with permissions.
5848      * @hide
5849      */
5850     void grantAppPermission(Account account, String authTokenType, int uid) {
5851         if (account == null || authTokenType == null) {
5852             Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
5853             return;
5854         }
5855         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
5856         synchronized (accounts.dbLock) {
5857             synchronized (accounts.cacheLock) {
5858                 long accountId = accounts.accountsDb.findDeAccountId(account);
5859                 if (accountId >= 0) {
5860                     accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5861                 }
5862                 cancelNotification(
5863                         getCredentialPermissionNotificationId(account, authTokenType, uid),
5864                         UserHandle.of(accounts.userId));
5865 
5866                 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5867             }
5868         }
5869 
5870         // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5871         for (AccountManagerInternal.OnAppPermissionChangeListener listener
5872                 : mAppPermissionChangeListeners) {
5873             mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5874         }
5875     }
5876 
5877     /**
5878      * Don't allow callers with the given uid permission to get credentials for
5879      * account/authTokenType.
5880      * <p>
5881      * Although this is public it can only be accessed via the AccountManagerService object
5882      * which is in the system. This means we don't need to protect it with permissions.
5883      * @hide
5884      */
5885     private void revokeAppPermission(Account account, String authTokenType, int uid) {
5886         if (account == null || authTokenType == null) {
5887             Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
5888             return;
5889         }
5890         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
5891         synchronized (accounts.dbLock) {
5892             synchronized (accounts.cacheLock) {
5893                 accounts.accountsDb.beginTransaction();
5894                 try {
5895                     long accountId = accounts.accountsDb.findDeAccountId(account);
5896                     if (accountId >= 0) {
5897                         accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5898                                 accountId, authTokenType, uid);
5899                         accounts.accountsDb.setTransactionSuccessful();
5900                     }
5901                 } finally {
5902                     accounts.accountsDb.endTransaction();
5903                 }
5904 
5905                 cancelNotification(
5906                         getCredentialPermissionNotificationId(account, authTokenType, uid),
5907                         UserHandle.of(accounts.userId));
5908             }
5909         }
5910 
5911         // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5912         for (AccountManagerInternal.OnAppPermissionChangeListener listener
5913                 : mAppPermissionChangeListeners) {
5914             mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5915         }
5916     }
5917 
5918     private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5919         final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
5920         if (oldAccountsForType != null) {
5921             ArrayList<Account> newAccountsList = new ArrayList<>();
5922             for (Account curAccount : oldAccountsForType) {
5923                 if (!curAccount.equals(account)) {
5924                     newAccountsList.add(curAccount);
5925                 }
5926             }
5927             if (newAccountsList.isEmpty()) {
5928                 accounts.accountCache.remove(account.type);
5929             } else {
5930                 Account[] newAccountsForType = new Account[newAccountsList.size()];
5931                 newAccountsForType = newAccountsList.toArray(newAccountsForType);
5932                 accounts.accountCache.put(account.type, newAccountsForType);
5933             }
5934         }
5935         accounts.userDataCache.remove(account);
5936         accounts.authTokenCache.remove(account);
5937         accounts.previousNameCache.remove(account);
5938         accounts.visibilityCache.remove(account);
5939 
5940         AccountManager.invalidateLocalAccountsDataCaches();
5941     }
5942 
5943     /**
5944      * This assumes that the caller has already checked that the account is not already present.
5945      * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5946      * processes and if you will return this account to apps you should return the result.
5947      * @return The inserted account which is a new instance that is being tracked.
5948      */
5949     private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
5950         Account[] accountsForType = accounts.accountCache.get(account.type);
5951         int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5952         Account[] newAccountsForType = new Account[oldLength + 1];
5953         if (accountsForType != null) {
5954             System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
5955         }
5956         String token = account.getAccessId() != null ? account.getAccessId()
5957                 : UUID.randomUUID().toString();
5958         newAccountsForType[oldLength] = new Account(account, token);
5959         accounts.accountCache.put(account.type, newAccountsForType);
5960         AccountManager.invalidateLocalAccountsDataCaches();
5961         return newAccountsForType[oldLength];
5962     }
5963 
5964     @NonNull
5965     private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
5966             @Nullable String callingPackage, boolean includeManagedNotVisible) {
5967         String visibilityFilterPackage = callingPackage;
5968         if (visibilityFilterPackage == null) {
5969             visibilityFilterPackage = getPackageNameForUid(callingUid);
5970         }
5971         Map<Account, Integer> firstPass = new LinkedHashMap<>();
5972         for (Account account : unfiltered) {
5973             int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
5974             if ((visibility == AccountManager.VISIBILITY_VISIBLE
5975                     || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5976                     || (includeManagedNotVisible
5977                             && (visibility
5978                                     == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5979                 firstPass.put(account, visibility);
5980             }
5981         }
5982         Map<Account, Integer> secondPass =
5983                 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5984 
5985         Account[] filtered = new Account[secondPass.size()];
5986         filtered = secondPass.keySet().toArray(filtered);
5987         return filtered;
5988     }
5989 
5990     @NonNull
5991     private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
5992             @NonNull Map<Account, Integer> unfiltered, int callingUid,
5993             @Nullable String callingPackage) {
5994         // first part is to filter shared accounts.
5995         // unfiltered type check is not necessary.
5996         if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
5997                 || callingUid == Process.SYSTEM_UID) {
5998             return unfiltered;
5999         }
6000         UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
6001         if (user != null && user.isRestricted()) {
6002             String[] packages = mPackageManager.getPackagesForUid(callingUid);
6003             if (packages == null) {
6004                 packages = new String[] {};
6005             }
6006             // If any of the packages is a visible listed package, return the full set,
6007             // otherwise return non-shared accounts only.
6008             // This might be a temporary way to specify a visible list
6009             String visibleList = mContext.getResources().getString(
6010                     com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
6011             for (String packageName : packages) {
6012                 if (visibleList.contains(";" + packageName + ";")) {
6013                     return unfiltered;
6014                 }
6015             }
6016             Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
6017             if (ArrayUtils.isEmpty(sharedAccounts)) {
6018                 return unfiltered;
6019             }
6020             String requiredAccountType = "";
6021             try {
6022                 // If there's an explicit callingPackage specified, check if that package
6023                 // opted in to see restricted accounts.
6024                 if (callingPackage != null) {
6025                     PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
6026                     if (pi != null && pi.restrictedAccountType != null) {
6027                         requiredAccountType = pi.restrictedAccountType;
6028                     }
6029                 } else {
6030                     // Otherwise check if the callingUid has a package that has opted in
6031                     for (String packageName : packages) {
6032                         PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
6033                         if (pi != null && pi.restrictedAccountType != null) {
6034                             requiredAccountType = pi.restrictedAccountType;
6035                             break;
6036                         }
6037                     }
6038                 }
6039             } catch (NameNotFoundException e) {
6040                 Log.d(TAG, "Package not found " + e.getMessage());
6041             }
6042             Map<Account, Integer> filtered = new LinkedHashMap<>();
6043             for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
6044                 Account account = entry.getKey();
6045                 if (account.type.equals(requiredAccountType)) {
6046                     filtered.put(account, entry.getValue());
6047                 } else {
6048                     boolean found = false;
6049                     for (Account shared : sharedAccounts) {
6050                         if (shared.equals(account)) {
6051                             found = true;
6052                             break;
6053                         }
6054                     }
6055                     if (!found) {
6056                         filtered.put(account, entry.getValue());
6057                     }
6058                 }
6059             }
6060             return filtered;
6061         } else {
6062             return unfiltered;
6063         }
6064     }
6065 
6066     /*
6067      * packageName can be null. If not null, it should be used to filter out restricted accounts
6068      * that the package is not allowed to access.
6069      *
6070      * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
6071      * deadlock
6072      */
6073     @NonNull
6074     protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
6075             int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
6076         Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
6077                 "Method should not be called with cacheLock");
6078         if (accountType != null) {
6079             Account[] accounts;
6080             synchronized (userAccounts.cacheLock) {
6081                 accounts = userAccounts.accountCache.get(accountType);
6082             }
6083             if (accounts == null) {
6084                 return EMPTY_ACCOUNT_ARRAY;
6085             } else {
6086                 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
6087                         callingUid, callingPackage, includeManagedNotVisible);
6088             }
6089         } else {
6090             int totalLength = 0;
6091             Account[] accountsArray;
6092             synchronized (userAccounts.cacheLock) {
6093                 for (Account[] accounts : userAccounts.accountCache.values()) {
6094                     totalLength += accounts.length;
6095                 }
6096                 if (totalLength == 0) {
6097                     return EMPTY_ACCOUNT_ARRAY;
6098                 }
6099                 accountsArray = new Account[totalLength];
6100                 totalLength = 0;
6101                 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
6102                     System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
6103                             accountsOfType.length);
6104                     totalLength += accountsOfType.length;
6105                 }
6106             }
6107             return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
6108                     includeManagedNotVisible);
6109         }
6110     }
6111 
6112     /** protected by the {@code dbLock}, {@code cacheLock} */
6113     protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
6114             Account account, String key, String value) {
6115         Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
6116         if (userDataForAccount == null) {
6117             userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6118             accounts.userDataCache.put(account, userDataForAccount);
6119         }
6120         if (value == null) {
6121             userDataForAccount.remove(key);
6122         } else {
6123             userDataForAccount.put(key, value);
6124         }
6125     }
6126 
6127     protected String readCachedTokenInternal(
6128             UserAccounts accounts,
6129             Account account,
6130             String tokenType,
6131             String callingPackage,
6132             byte[] pkgSigDigest) {
6133         synchronized (accounts.cacheLock) {
6134             return accounts.accountTokenCaches.get(
6135                     account, tokenType, callingPackage, pkgSigDigest);
6136         }
6137     }
6138 
6139     /** protected by the {@code dbLock}, {@code cacheLock} */
6140     protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
6141             Account account, String key, String value) {
6142         Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6143         if (authTokensForAccount == null) {
6144             authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6145             accounts.authTokenCache.put(account, authTokensForAccount);
6146         }
6147         if (value == null) {
6148             authTokensForAccount.remove(key);
6149         } else {
6150             authTokensForAccount.put(key, value);
6151         }
6152     }
6153 
6154     protected String readAuthTokenInternal(UserAccounts accounts, Account account,
6155             String authTokenType) {
6156         // Fast path - check if account is already cached
6157         synchronized (accounts.cacheLock) {
6158             Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6159             if (authTokensForAccount != null) {
6160                 return authTokensForAccount.get(authTokenType);
6161             }
6162         }
6163         // If not cached yet - do slow path and sync with db if necessary
6164         synchronized (accounts.dbLock) {
6165             synchronized (accounts.cacheLock) {
6166                 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6167                 if (authTokensForAccount == null) {
6168                     // need to populate the cache for this account
6169                     authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6170                     accounts.authTokenCache.put(account, authTokensForAccount);
6171                 }
6172                 return authTokensForAccount.get(authTokenType);
6173             }
6174         }
6175     }
6176 
6177     private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
6178         Map<String, String> userDataForAccount;
6179         // Fast path - check if data is already cached
6180         synchronized (accounts.cacheLock) {
6181             userDataForAccount = accounts.userDataCache.get(account);
6182         }
6183         // If not cached yet - do slow path and sync with db if necessary
6184         if (userDataForAccount == null) {
6185             synchronized (accounts.dbLock) {
6186                 synchronized (accounts.cacheLock) {
6187                     userDataForAccount = accounts.userDataCache.get(account);
6188                     if (userDataForAccount == null) {
6189                         // need to populate the cache for this account
6190                         userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6191                         accounts.userDataCache.put(account, userDataForAccount);
6192                     }
6193                 }
6194             }
6195         }
6196         return userDataForAccount.get(key);
6197     }
6198 
6199     private Context getContextForUser(UserHandle user) {
6200         try {
6201             return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
6202         } catch (NameNotFoundException e) {
6203             // Default to mContext, not finding the package system is running as is unlikely.
6204             return mContext;
6205         }
6206     }
6207 
6208     private void sendResponse(IAccountManagerResponse response, Bundle result) {
6209         try {
6210             response.onResult(result);
6211         } catch (RemoteException e) {
6212             // if the caller is dead then there is no one to care about remote
6213             // exceptions
6214             if (Log.isLoggable(TAG, Log.VERBOSE)) {
6215                 Log.v(TAG, "failure while notifying response", e);
6216             }
6217         }
6218     }
6219 
6220     private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6221             String errorMessage) {
6222         try {
6223             response.onError(errorCode, errorMessage);
6224         } catch (RemoteException e) {
6225             // if the caller is dead then there is no one to care about remote
6226             // exceptions
6227             if (Log.isLoggable(TAG, Log.VERBOSE)) {
6228                 Log.v(TAG, "failure while notifying response", e);
6229             }
6230         }
6231     }
6232 
6233     private final class AccountManagerInternalImpl extends AccountManagerInternal {
6234         private final Object mLock = new Object();
6235 
6236         @GuardedBy("mLock")
6237         private AccountManagerBackupHelper mBackupHelper;
6238 
6239         @Override
6240         public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6241                 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6242             if (account == null) {
6243                 Slog.w(TAG, "account cannot be null");
6244                 return;
6245             }
6246             if (packageName == null) {
6247                 Slog.w(TAG, "packageName cannot be null");
6248                 return;
6249             }
6250             if (userId < UserHandle.USER_SYSTEM) {
6251                 Slog.w(TAG, "user id must be concrete");
6252                 return;
6253             }
6254             if (callback == null) {
6255                 Slog.w(TAG, "callback cannot be null");
6256                 return;
6257             }
6258 
6259             int visibility =
6260                 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6261             if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6262                 Slog.w(TAG, "requestAccountAccess: account is hidden");
6263                 return;
6264             }
6265 
6266             if (AccountManagerService.this.hasAccountAccess(account, packageName,
6267                     new UserHandle(userId))) {
6268                 Bundle result = new Bundle();
6269                 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6270                 callback.sendResult(result);
6271                 return;
6272             }
6273 
6274             final int uid;
6275             try {
6276                 final long identityToken = clearCallingIdentity();
6277                 try {
6278                     uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6279                 } finally {
6280                     restoreCallingIdentity(identityToken);
6281                 }
6282             } catch (NameNotFoundException e) {
6283                 Slog.e(TAG, "Unknown package " + packageName);
6284                 return;
6285             }
6286 
6287             Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
6288             final UserAccounts userAccounts;
6289             synchronized (mUsers) {
6290                 userAccounts = mUsers.get(userId);
6291             }
6292             SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
6293             doNotification(userAccounts, account, null, intent, packageName, userId);
6294         }
6295 
6296         @Override
6297         public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6298             // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6299             mAppPermissionChangeListeners.add(listener);
6300         }
6301 
6302         @Override
6303         public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6304             return AccountManagerService.this.hasAccountAccess(account, null, uid);
6305         }
6306 
6307         @Override
6308         public byte[] backupAccountAccessPermissions(int userId) {
6309             synchronized (mLock) {
6310                 if (mBackupHelper == null) {
6311                     mBackupHelper = new AccountManagerBackupHelper(
6312                             AccountManagerService.this, this);
6313                 }
6314                 return mBackupHelper.backupAccountAccessPermissions(userId);
6315             }
6316         }
6317 
6318         @Override
6319         public void restoreAccountAccessPermissions(byte[] data, int userId) {
6320             synchronized (mLock) {
6321                 if (mBackupHelper == null) {
6322                     mBackupHelper = new AccountManagerBackupHelper(
6323                             AccountManagerService.this, this);
6324                 }
6325                 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6326             }
6327         }
6328     }
6329 
6330     @VisibleForTesting
6331     static class Injector {
6332         private final Context mContext;
6333 
6334         public Injector(Context context) {
6335             mContext = context;
6336         }
6337 
6338         Looper getMessageHandlerLooper() {
6339             ServiceThread serviceThread = new ServiceThread(TAG,
6340                     android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6341             serviceThread.start();
6342             return serviceThread.getLooper();
6343         }
6344 
6345         Context getContext() {
6346             return mContext;
6347         }
6348 
6349         void addLocalService(AccountManagerInternal service) {
6350             LocalServices.addService(AccountManagerInternal.class, service);
6351         }
6352 
6353         String getDeDatabaseName(int userId) {
6354             File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6355                     AccountsDb.DE_DATABASE_NAME);
6356             return databaseFile.getPath();
6357         }
6358 
6359         String getCeDatabaseName(int userId) {
6360             File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6361                     AccountsDb.CE_DATABASE_NAME);
6362             return databaseFile.getPath();
6363         }
6364 
6365         String getPreNDatabaseName(int userId) {
6366             File systemDir = Environment.getDataSystemDirectory();
6367             File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6368                     PRE_N_DATABASE_NAME);
6369             if (userId == 0) {
6370                 // Migrate old file, if it exists, to the new location.
6371                 // Make sure the new file doesn't already exist. A placeholder file could have been
6372                 // accidentally created in the old location,
6373                 // causing the new one to become corrupted as well.
6374                 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6375                 if (oldFile.exists() && !databaseFile.exists()) {
6376                     // Check for use directory; create if it doesn't exist, else renameTo will fail
6377                     File userDir = Environment.getUserSystemDirectory(userId);
6378                     if (!userDir.exists()) {
6379                         if (!userDir.mkdirs()) {
6380                             throw new IllegalStateException(
6381                                     "User dir cannot be created: " + userDir);
6382                         }
6383                     }
6384                     if (!oldFile.renameTo(databaseFile)) {
6385                         throw new IllegalStateException(
6386                                 "User dir cannot be migrated: " + databaseFile);
6387                     }
6388                 }
6389             }
6390             return databaseFile.getPath();
6391         }
6392 
6393         IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6394             return new AccountAuthenticatorCache(mContext);
6395         }
6396 
6397         INotificationManager getNotificationManager() {
6398             return NotificationManager.getService();
6399         }
6400     }
6401 
6402     private static class NotificationId {
6403         final String mTag;
6404         private final int mId;
6405 
6406         NotificationId(String tag, int type) {
6407             mTag = tag;
6408             mId = type;
6409         }
6410     }
6411 }
6412