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