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