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