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