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