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