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