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