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