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