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