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