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