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