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