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