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