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