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