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