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