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