blob: debc2a1169345d8f623b59c140d36d9bc9e41181 [file] [log] [blame]
Fred Quintana60307342009-03-24 22:48:12 -07001/*
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
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.accounts;
Fred Quintana60307342009-03-24 22:48:12 -070018
Doug Zongker885cfc232009-10-21 16:52:44 -070019import android.Manifest;
Carlos Valdivia91979be2015-05-22 14:11:35 -070020import android.accounts.AbstractAccountAuthenticator;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080021import android.accounts.Account;
22import android.accounts.AccountAndUser;
23import android.accounts.AccountAuthenticatorResponse;
24import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070025import android.accounts.AccountManagerInternal;
sunjianf29d5492017-05-11 15:42:31 -070026import android.accounts.AccountManagerResponse;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080027import android.accounts.AuthenticatorDescription;
Amith Yamasani23c8b962013-04-10 13:37:18 -070028import android.accounts.CantAddAccountActivity;
sunjianf29d5492017-05-11 15:42:31 -070029import android.accounts.ChooseAccountActivity;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080030import android.accounts.GrantCredentialsPermissionActivity;
31import android.accounts.IAccountAuthenticator;
32import android.accounts.IAccountAuthenticatorResponse;
33import android.accounts.IAccountManager;
34import android.accounts.IAccountManagerResponse;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070035import android.annotation.IntRange;
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070036import android.annotation.NonNull;
Svet Ganovf6d424f12016-09-20 20:18:53 -070037import android.annotation.Nullable;
Brett Chabot3b4fcbc2011-01-09 13:41:02 -080038import android.app.ActivityManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070039import android.app.ActivityThread;
Svetoslavf3f02ac2015-09-08 14:36:35 -070040import android.app.AppOpsManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070041import android.app.INotificationManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070042import android.app.Notification;
43import android.app.NotificationManager;
44import android.app.PendingIntent;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000045import android.app.admin.DeviceAdminInfo;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010046import android.app.admin.DevicePolicyManager;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000047import android.app.admin.DevicePolicyManagerInternal;
Fred Quintanaa698f422009-04-08 19:14:54 -070048import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070049import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070050import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070053import android.content.IntentSender;
Fred Quintanab839afc2009-10-14 15:57:28 -070054import android.content.ServiceConnection;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -080055import android.content.pm.ActivityInfo;
Doug Zongker885cfc232009-10-21 16:52:44 -070056import android.content.pm.ApplicationInfo;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070057import android.content.pm.IPackageManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070058import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070059import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070060import android.content.pm.PackageManager.NameNotFoundException;
Dan Cashman303c4bb2018-04-10 07:41:16 -070061import android.content.pm.PackageManagerInternal;
62import android.content.pm.PackageParser;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070063import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070064import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070065import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070066import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070067import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070068import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070069import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070070import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070071import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080072import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070073import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070074import android.os.IBinder;
75import android.os.Looper;
76import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070077import android.os.Parcel;
sunjianf29d5492017-05-11 15:42:31 -070078import android.os.Parcelable;
Amith Yamasani27db4682013-03-30 17:07:47 -070079import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070080import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070081import android.os.RemoteException;
Hongming Jin8e2bfc12018-05-30 11:01:06 -070082import android.os.ResultReceiver;
83import android.os.ShellCallback;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080084import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070085import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070086import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070087import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070088import android.text.TextUtils;
89import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070090import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070091import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080092import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070093import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070094
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070095import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070096import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070097import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070098import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040099import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500100import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -0800101import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600102import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800103import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -0700104import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +0000105import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700106import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600107import com.android.server.SystemService;
108
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700109import com.google.android.collect.Lists;
110import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700111
Oscar Montemayora8529f62009-11-18 10:14:20 -0800112import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700113import java.io.FileDescriptor;
114import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800115import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700116import java.security.MessageDigest;
117import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700118import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700119import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800120import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700121import java.util.Collection;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700122import java.util.Collections;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700123import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700124import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700125import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800126import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700127import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800128import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800129import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700130import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700131import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700132import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700133import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700134import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700135
Fred Quintana60307342009-03-24 22:48:12 -0700136/**
137 * A system service that provides account, password, and authtoken management for all
138 * accounts on the device. Some of these calls are implemented with the help of the corresponding
139 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
140 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700141 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700142 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700143 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700144public class AccountManagerService
145 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800146 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700147 private static final String TAG = "AccountManagerService";
148
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600149 public static class Lifecycle extends SystemService {
150 private AccountManagerService mService;
151
152 public Lifecycle(Context context) {
153 super(context);
154 }
155
156 @Override
157 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700158 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600159 publishBinderService(Context.ACCOUNT_SERVICE, mService);
160 }
161
162 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600163 public void onUnlockUser(int userHandle) {
164 mService.onUnlockUser(userHandle);
165 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700166
167 @Override
Fyodor Kupolovce25ed22017-05-04 11:44:31 -0700168 public void onStopUser(int userHandle) {
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700169 Slog.i(TAG, "onStopUser " + userHandle);
170 mService.purgeUserData(userHandle);
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700171 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600172 }
173
Svet Ganov5d09c992016-09-07 09:57:41 -0700174 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700175
Fred Quintana56285a62010-12-02 14:20:51 -0800176 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700177 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700178 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700179 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800180
Svet Ganov5d09c992016-09-07 09:57:41 -0700181 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700182
Fred Quintana60307342009-03-24 22:48:12 -0700183 // Messages that can be sent on mHandler
184 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700185 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700186
Fred Quintana56285a62010-12-02 14:20:51 -0800187 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700188 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700189 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800190
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800191 private static final int SIGNATURE_CHECK_MISMATCH = 0;
192 private static final int SIGNATURE_CHECK_MATCH = 1;
193 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
194
Carlos Valdivia91979be2015-05-22 14:11:35 -0700195 static {
196 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800197 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
198 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700199 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700200
201 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700202
Amith Yamasani04e0d262012-02-14 11:50:53 -0800203 static class UserAccounts {
204 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700205 final AccountsDb accountsDb;
Chris Wren717a8812017-03-31 15:34:39 -0400206 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
207 credentialsPermissionNotificationIds = new HashMap<>();
208 private final HashMap<Account, NotificationId> signinRequiredNotificationIds
209 = new HashMap<>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700210 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700211 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800212 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700213 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800214 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700215 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800216 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700217 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700218 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700219 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700220 /** protected by the {@link #cacheLock} */
221 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700222
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700223 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700224 * type -> (packageName -> number of active receivers)
225 * type == null is used to get notifications about all account types
226 */
227 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800228
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700229 /**
230 * protected by the {@link #cacheLock}
231 *
232 * Caches the previous names associated with an account. Previous names
233 * should be cached because we expect that when an Account is renamed,
234 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
235 * want to know if the accounts they care about have been renamed.
236 *
237 * The previous names are wrapped in an {@link AtomicReference} so that
238 * we can distinguish between those accounts with no previous names and
239 * those whose previous names haven't been cached (yet).
240 */
241 private final HashMap<Account, AtomicReference<String>> previousNameCache =
242 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800243
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700244 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800245 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700246 synchronized (dbLock) {
247 synchronized (cacheLock) {
248 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
249 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800250 }
251 }
252 }
253
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700254 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600255 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700256 // Not thread-safe. Only use in synchronized context
257 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700258 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
259 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800260
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700261 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700262 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700263
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700264 /**
265 * This should only be called by system code. One should only call this after the service
266 * has started.
267 * @return a reference to the AccountManagerService instance
268 * @hide
269 */
270 public static AccountManagerService getSingleton() {
271 return sThis.get();
272 }
Fred Quintana60307342009-03-24 22:48:12 -0700273
Fyodor Kupolovda993802016-09-21 14:47:10 -0700274 public AccountManagerService(Injector injector) {
275 mInjector = injector;
276 mContext = injector.getContext();
277 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700278 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700279 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
280 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800281 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700282
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700283 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800284
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800285 IntentFilter intentFilter = new IntentFilter();
286 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
287 intentFilter.addDataScheme("package");
288 mContext.registerReceiver(new BroadcastReceiver() {
289 @Override
290 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700291 // Don't delete accounts when updating a authenticator's
292 // package.
293 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700294 /* Purging data requires file io, don't block the main thread. This is probably
295 * less than ideal because we are introducing a race condition where old grants
296 * could be exercised until they are purged. But that race condition existed
297 * anyway with the broadcast receiver.
298 *
299 * Ideally, we would completely clear the cache, purge data from the database,
300 * and then rebuild the cache. All under the cache lock. But that change is too
301 * large at this point.
302 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800303 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700304 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700305 @Override
306 public void run() {
307 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800308 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800309 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700310 }
311 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700312 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700313 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800314 }
315 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800316
Fyodor Kupolovda993802016-09-21 14:47:10 -0700317 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700318
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700319 IntentFilter userFilter = new IntentFilter();
320 userFilter.addAction(Intent.ACTION_USER_REMOVED);
321 mContext.registerReceiverAsUser(new BroadcastReceiver() {
322 @Override
323 public void onReceive(Context context, Intent intent) {
324 String action = intent.getAction();
325 if (Intent.ACTION_USER_REMOVED.equals(action)) {
326 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
327 if (userId < 1) return;
328 Slog.i(TAG, "User " + userId + " removed");
329 purgeUserData(userId);
330 }
331 }
332 }, UserHandle.ALL, userFilter, null, null);
333
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700334 // Need to cancel account request notifications if the update/install can access the account
335 new PackageMonitor() {
336 @Override
337 public void onPackageAdded(String packageName, int uid) {
338 // Called on a handler, and running as the system
339 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
340 }
341
342 @Override
343 public void onPackageUpdateFinished(String packageName, int uid) {
344 // Called on a handler, and running as the system
345 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
346 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700347 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700348
349 // Cancel account request notification if an app op was preventing the account access
350 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
351 new AppOpsManager.OnOpChangedInternalListener() {
352 @Override
353 public void onOpChanged(int op, String packageName) {
354 try {
355 final int userId = ActivityManager.getCurrentUser();
356 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
357 final int mode = mAppOpsManager.checkOpNoThrow(
358 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
359 if (mode == AppOpsManager.MODE_ALLOWED) {
360 final long identity = Binder.clearCallingIdentity();
361 try {
362 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
363 } finally {
364 Binder.restoreCallingIdentity(identity);
365 }
366 }
367 } catch (NameNotFoundException e) {
368 /* ignore */
369 }
370 }
371 });
372
373 // Cancel account request notification if a permission was preventing the account access
374 mPackageManager.addOnPermissionsChangeListener(
375 (int uid) -> {
376 Account[] accounts = null;
377 String[] packageNames = mPackageManager.getPackagesForUid(uid);
378 if (packageNames != null) {
379 final int userId = UserHandle.getUserId(uid);
380 final long identity = Binder.clearCallingIdentity();
381 try {
382 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800383 // if app asked for permission we need to cancel notification even
384 // for O+ applications.
385 if (mPackageManager.checkPermission(
386 Manifest.permission.GET_ACCOUNTS,
387 packageName) != PackageManager.PERMISSION_GRANTED) {
388 continue;
389 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700390
391 if (accounts == null) {
392 accounts = getAccountsAsUser(null, userId, "android");
393 if (ArrayUtils.isEmpty(accounts)) {
394 return;
395 }
396 }
397
398 for (Account account : accounts) {
399 cancelAccountAccessRequestNotificationIfNeeded(
400 account, uid, packageName, true);
401 }
402 }
403 } finally {
404 Binder.restoreCallingIdentity(identity);
405 }
406 }
407 });
408 }
409
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700410
411 boolean getBindInstantServiceAllowed(int userId) {
412 return mAuthenticatorCache.getBindInstantServiceAllowed(userId);
413 }
414
415 void setBindInstantServiceAllowed(int userId, boolean allowed) {
416 mAuthenticatorCache.setBindInstantServiceAllowed(userId, allowed);
417 }
418
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700419 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
420 boolean checkAccess) {
421 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
422 for (Account account : accounts) {
423 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
424 }
425 }
426
427 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
428 boolean checkAccess) {
429 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
430 for (Account account : accounts) {
431 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
432 }
433 }
434
435 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
436 boolean checkAccess) {
437 String[] packageNames = mPackageManager.getPackagesForUid(uid);
438 if (packageNames != null) {
439 for (String packageName : packageNames) {
440 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
441 packageName, checkAccess);
442 }
443 }
444 }
445
446 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
447 int uid, String packageName, boolean checkAccess) {
448 if (!checkAccess || hasAccountAccess(account, packageName,
449 UserHandle.getUserHandleForUid(uid))) {
450 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700451 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700452 UserHandle.getUserHandleForUid(uid));
453 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800454 }
455
Dianne Hackborn164371f2013-10-01 19:10:13 -0700456 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800457 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800458 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800459 Bundle.setDefusable(extras, true);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700460 int callingUid = Binder.getCallingUid();
461 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800462 if (Log.isLoggable(TAG, Log.VERBOSE)) {
463 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
464 + ", pid " + Binder.getCallingPid());
465 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +0000466 Objects.requireNonNull(account, "account cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800467 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
468 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
469 callingUid, account.type);
470 throw new SecurityException(msg);
471 }
472 /*
473 * Child users are not allowed to add accounts. Only the accounts that are shared by the
474 * parent profile can be added to child profile.
475 *
476 * TODO: Only allow accounts that were shared to be added by a limited user.
477 */
478 // fails if the account already exists
479 long identityToken = clearCallingIdentity();
480 try {
481 UserAccounts accounts = getUserAccounts(userId);
482 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800483 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800484 } finally {
485 restoreCallingIdentity(identityToken);
486 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700487 }
488
489 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800490 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
491 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800492 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700493 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800494 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700495 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800496
497 if ((accountType != null && !managedTypes.contains(accountType))
498 || (accountType == null && !isSystemUid)) {
499 throw new SecurityException(
500 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
501 + callingUid + " with packageName=" + packageName);
502 }
503 if (accountType != null) {
504 managedTypes = new ArrayList<String>();
505 managedTypes.add(accountType);
506 }
507
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800508 long identityToken = clearCallingIdentity();
509 try {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700510 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800511 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700512 accounts);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800513 } finally {
514 restoreCallingIdentity(identityToken);
515 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800516 }
517
518 /*
519 * accountTypes may not be null
520 */
521 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
522 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700523 if (!packageExistsForUser(packageName, accounts.userId)) {
524 Log.d(TAG, "Package not found " + packageName);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800525 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800526 }
527
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800528 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800529 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700530 synchronized (accounts.dbLock) {
531 synchronized (accounts.cacheLock) {
532 final Account[] accountsOfType = accounts.accountCache.get(accountType);
533 if (accountsOfType != null) {
534 for (Account account : accountsOfType) {
535 result.put(account,
536 resolveAccountVisibility(account, packageName, accounts));
537 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800538 }
539 }
540 }
541 }
542 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800543 }
544
545 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800546 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +0000547 Objects.requireNonNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700548 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700549 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800550 if (!isAccountManagedByCaller(account.type, callingUid, userId)
551 && !isSystemUid(callingUid)) {
552 String msg =
553 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700554 throw new SecurityException(msg);
555 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700556
557 long identityToken = clearCallingIdentity();
558 try {
559 UserAccounts accounts = getUserAccounts(userId);
560 synchronized (accounts.dbLock) {
561 synchronized (accounts.cacheLock) {
562 return getPackagesAndVisibilityForAccountLocked(account, accounts);
563 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700564 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700565 } finally {
566 restoreCallingIdentity(identityToken);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700567 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700568
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800569 }
570
571 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700572 * Returns Map with all package names and visibility values for given account.
573 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800574 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800575 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800576 * @param accounts UserAccount that currently hosts the account and application
577 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700578 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800579 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700580 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800581 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700582 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
583 if (accountVisibility == null) {
584 Log.d(TAG, "Visibility was not initialized");
585 accountVisibility = new HashMap<>();
586 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800587 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700588 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700589 }
590
591 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700592 public int getAccountVisibility(Account account, String packageName) {
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +0000593 Objects.requireNonNull(account, "account cannot be null");
594 Objects.requireNonNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800595 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700596 int userId = UserHandle.getCallingUserId();
597 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800598 && !isSystemUid(callingUid)) {
599 String msg = String.format(
600 "uid %s cannot get secrets for accounts of type: %s",
601 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700602 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800603 throw new SecurityException(msg);
604 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700605 long identityToken = clearCallingIdentity();
606 try {
607 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyevcbe1bd12017-04-25 17:02:47 -0700608 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
609 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
610 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
611 return visibility;
612 } else {
613 return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
614 }
615 }
616 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) {
617 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
618 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
619 return visibility;
620 } else {
621 return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
622 }
623 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700624 return resolveAccountVisibility(account, packageName, accounts);
625 } finally {
626 restoreCallingIdentity(identityToken);
627 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800628 }
629
630 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800631 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800632 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800633 * @param account The account to check visibility.
634 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800635 * @param accounts UserAccount that currently hosts the account and application
636 *
637 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
638 *
639 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700640 private int getAccountVisibilityFromCache(Account account, String packageName,
641 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700642 synchronized (accounts.cacheLock) {
643 Map<String, Integer> accountVisibility =
644 getPackagesAndVisibilityForAccountLocked(account, accounts);
645 Integer visibility = accountVisibility.get(packageName);
646 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800647 }
648 }
649
650 /**
651 * Method which handles default values for Account visibility.
652 *
653 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800654 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800655 * @param accounts UserAccount that currently hosts the account and application
656 *
657 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
658 *
659 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800660 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800661 UserAccounts accounts) {
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +0000662 Objects.requireNonNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800663 int uid = -1;
664 try {
665 long identityToken = clearCallingIdentity();
666 try {
667 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
668 } finally {
669 restoreCallingIdentity(identityToken);
670 }
671 } catch (NameNotFoundException e) {
672 Log.d(TAG, "Package not found " + e.getMessage());
673 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800674 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800675
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800676 // System visibility can not be restricted.
677 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
678 return AccountManager.VISIBILITY_VISIBLE;
679 }
680
681 int signatureCheckResult =
682 checkPackageSignature(account.type, uid, accounts.userId);
683
684 // Authenticator can not restrict visibility to itself.
685 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
686 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
687 }
688
689 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700690 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800691
692 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
693 return visibility;
694 }
695
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -0700696 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800697 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
698
699 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800700 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800701 return AccountManager.VISIBILITY_VISIBLE;
702 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800703
704 boolean preO = isPreOApplication(packageName);
705 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -0700706 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
707 || (checkReadContactsPermission(packageName, accounts.userId)
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700708 && accountTypeManagesContacts(account.type, accounts.userId))
709 || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800710 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
711 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700712 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800713 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800714 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
715 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
716 }
717 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700718 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800719 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800720 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
721 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
722 }
723 }
724 return visibility;
725 }
726
727 /**
728 * Checks targetSdk for a package;
729 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800730 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800731 *
732 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
733 * undefined
734 */
735 private boolean isPreOApplication(String packageName) {
736 try {
737 long identityToken = clearCallingIdentity();
738 ApplicationInfo applicationInfo;
739 try {
740 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
741 } finally {
742 restoreCallingIdentity(identityToken);
743 }
744
745 if (applicationInfo != null) {
746 int version = applicationInfo.targetSdkVersion;
747 return version < android.os.Build.VERSION_CODES.O;
748 }
749 return true;
750 } catch (NameNotFoundException e) {
751 Log.d(TAG, "Package not found " + e.getMessage());
752 return true;
753 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800754 }
755
756 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700757 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +0000758 Objects.requireNonNull(account, "account cannot be null");
759 Objects.requireNonNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800760 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700761 int userId = UserHandle.getCallingUserId();
762 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800763 && !isSystemUid(callingUid)) {
764 String msg = String.format(
765 "uid %s cannot get secrets for accounts of type: %s",
766 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700767 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800768 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700769 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700770 long identityToken = clearCallingIdentity();
771 try {
772 UserAccounts accounts = getUserAccounts(userId);
773 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700774 accounts);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700775 } finally {
776 restoreCallingIdentity(identityToken);
777 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700778 }
779
sunjian066aa5e2017-06-05 12:16:59 -0700780 private boolean isVisible(int visibility) {
781 return visibility == AccountManager.VISIBILITY_VISIBLE ||
782 visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
783 }
784
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700785 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800786 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700787 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800788 * @param account Account to update visibility.
789 * @param packageName Package name for which visibility is updated.
790 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800791 * @param notify if the flag is set applications will get notification about visibility change
792 * @param accounts UserAccount that currently hosts the account and application
793 *
794 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700795 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800796 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800797 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700798 synchronized (accounts.dbLock) {
799 synchronized (accounts.cacheLock) {
800 Map<String, Integer> packagesToVisibility;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700801 List<String> accountRemovedReceivers;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700802 if (notify) {
803 if (isSpecialPackageKey(packageName)) {
804 packagesToVisibility =
805 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700806 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700807 } else {
808 if (!packageExistsForUser(packageName, accounts.userId)) {
809 return false; // package is not installed.
810 }
811 packagesToVisibility = new HashMap<>();
812 packagesToVisibility.put(packageName,
813 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700814 accountRemovedReceivers = new ArrayList<>();
815 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
816 accountRemovedReceivers.add(packageName);
817 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700818 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800819 } else {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700820 // Notifications will not be send - only used during add account.
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700821 if (!isSpecialPackageKey(packageName) &&
822 !packageExistsForUser(packageName, accounts.userId)) {
823 // package is not installed and not meta value.
824 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100825 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700826 packagesToVisibility = Collections.emptyMap();
827 accountRemovedReceivers = Collections.emptyList();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800828 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700829
830 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800831 return false;
832 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800833
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700834 if (notify) {
835 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
836 .entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -0700837 int oldVisibility = packageToVisibility.getValue();
838 int currentVisibility =
839 resolveAccountVisibility(account, packageName, accounts);
840 if (isVisible(oldVisibility) != isVisible(currentVisibility)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700841 notifyPackage(packageToVisibility.getKey(), accounts);
842 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700843 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700844 for (String packageNameToNotify : accountRemovedReceivers) {
845 sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
846 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700847 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700848 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700849 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800850 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700851 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700852 }
853
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700854 // Update account visibility in cache and database.
855 private boolean updateAccountVisibilityLocked(Account account, String packageName,
856 int newVisibility, UserAccounts accounts) {
857 final long accountId = accounts.accountsDb.findDeAccountId(account);
858 if (accountId < 0) {
859 return false;
860 }
861
862 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
863 try {
864 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
865 newVisibility)) {
866 return false;
867 }
868 } finally {
869 StrictMode.setThreadPolicy(oldPolicy);
870 }
871 Map<String, Integer> accountVisibility =
872 getPackagesAndVisibilityForAccountLocked(account, accounts);
873 accountVisibility.put(packageName, newVisibility);
874 return true;
875 }
876
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700877 @Override
878 public void registerAccountListener(String[] accountTypes, String opPackageName) {
879 int callingUid = Binder.getCallingUid();
880 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700881
882 int userId = UserHandle.getCallingUserId();
883 long identityToken = clearCallingIdentity();
884 try {
885 UserAccounts accounts = getUserAccounts(userId);
886 registerAccountListener(accountTypes, opPackageName, accounts);
887 } finally {
888 restoreCallingIdentity(identityToken);
889 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800890 }
891
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700892 private void registerAccountListener(String[] accountTypes, String opPackageName,
893 UserAccounts accounts) {
894 synchronized (accounts.mReceiversForType) {
895 if (accountTypes == null) {
896 // null for any type
897 accountTypes = new String[] {null};
898 }
899 for (String type : accountTypes) {
900 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
901 if (receivers == null) {
902 receivers = new HashMap<>();
903 accounts.mReceiversForType.put(type, receivers);
904 }
905 Integer cnt = receivers.get(opPackageName);
906 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800907 }
908 }
909 }
910
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700911 @Override
912 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
913 int callingUid = Binder.getCallingUid();
914 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700915 int userId = UserHandle.getCallingUserId();
916 long identityToken = clearCallingIdentity();
917 try {
918 UserAccounts accounts = getUserAccounts(userId);
919 unregisterAccountListener(accountTypes, opPackageName, accounts);
920 } finally {
921 restoreCallingIdentity(identityToken);
922 }
923 }
924
925 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
926 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700927 synchronized (accounts.mReceiversForType) {
928 if (accountTypes == null) {
929 // null for any type
930 accountTypes = new String[] {null};
931 }
932 for (String type : accountTypes) {
933 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
934 if (receivers == null || receivers.get(opPackageName) == null) {
935 throw new IllegalArgumentException("attempt to unregister wrong receiver");
936 }
937 Integer cnt = receivers.get(opPackageName);
938 if (cnt == 1) {
939 receivers.remove(opPackageName);
940 } else {
941 receivers.put(opPackageName, cnt - 1);
942 }
943 }
944 }
945 }
946
947 // Send notification to all packages which can potentially see the account
948 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
949 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700950
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700951 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700952 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
953 && (packageToVisibility.getValue()
954 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700955 notifyPackage(packageToVisibility.getKey(), accounts);
956 }
957 }
958 }
959
960 /**
961 * Sends a direct intent to a package, notifying it of account visibility change.
962 *
963 * @param packageName to send Account to
964 * @param accounts UserAccount that currently hosts the account
965 */
966 private void notifyPackage(String packageName, UserAccounts accounts) {
967 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
968 intent.setPackage(packageName);
969 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
970 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
971 }
972
973 // Returns a map from package name to visibility, for packages subscribed
974 // to notifications about any account type, or type of provided account
975 // account type or all types.
976 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
977 Set<String> packages = new HashSet<>();
978 synchronized (accounts.mReceiversForType) {
979 for (String type : new String[] {account.type, null}) {
980 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
981 if (receivers != null) {
982 packages.addAll(receivers.keySet());
983 }
984 }
985 }
986 Map<String, Integer> result = new HashMap<>();
987 for (String packageName : packages) {
988 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
989 }
990 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800991 }
992
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700993 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
994 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
995 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
996 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
997 List<ResolveInfo> receivers =
998 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
999 List<String> result = new ArrayList<>();
1000 if (receivers == null) {
1001 return result;
1002 }
1003 for (ResolveInfo resolveInfo: receivers) {
1004 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
1005 int visibility = resolveAccountVisibility(account, packageName, accounts);
1006 if (visibility == AccountManager.VISIBILITY_VISIBLE
1007 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1008 result.add(packageName);
1009 }
1010 }
1011 return result;
1012 }
1013
1014 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
1015 private boolean shouldNotifyPackageOnAccountRemoval(Account account,
1016 String packageName, UserAccounts accounts) {
1017 int visibility = resolveAccountVisibility(account, packageName, accounts);
1018 if (visibility != AccountManager.VISIBILITY_VISIBLE
1019 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1020 return false;
1021 }
1022
1023 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1024 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1025 intent.setPackage(packageName);
1026 List<ResolveInfo> receivers =
1027 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1028 return (receivers != null && receivers.size() > 0);
1029 }
1030
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001031 private boolean packageExistsForUser(String packageName, int userId) {
1032 try {
1033 long identityToken = clearCallingIdentity();
1034 try {
1035 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -07001036 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001037 } finally {
1038 restoreCallingIdentity(identityToken);
1039 }
1040 } catch (NameNotFoundException e) {
1041 return false;
1042 }
1043 }
1044
1045 /**
1046 * Returns true if packageName is one of special values.
1047 */
1048 private boolean isSpecialPackageKey(String packageName) {
1049 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1050 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1051 }
1052
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001053 private void sendAccountsChangedBroadcast(int userId) {
1054 Log.i(TAG, "the accounts changed, sending broadcast of "
1055 + ACCOUNTS_CHANGED_INTENT.getAction());
1056 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001057 }
1058
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001059 private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001060 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1061 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001062 intent.setPackage(packageName);
1063 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1064 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001065 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1066 }
1067
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001068 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -07001069 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1070 throws RemoteException {
1071 try {
1072 return super.onTransact(code, data, reply, flags);
1073 } catch (RuntimeException e) {
1074 // The account manager only throws security exceptions, so let's
1075 // log all others.
1076 if (!(e instanceof SecurityException)) {
1077 Slog.wtf(TAG, "Account Manager Crash", e);
1078 }
1079 throw e;
1080 }
1081 }
1082
Amith Yamasani258848d2012-08-10 17:06:33 -07001083 private UserManager getUserManager() {
1084 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -07001085 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -07001086 }
1087 return mUserManager;
1088 }
1089
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001090 /**
1091 * Validate internal set of accounts against installed authenticators for
1092 * given user. Clears cached authenticators before validating.
1093 */
1094 public void validateAccounts(int userId) {
1095 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001096 // Invalidate user-specific cache to make sure we catch any
1097 // removed authenticators.
1098 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1099 }
1100
1101 /**
1102 * Validate internal set of accounts against installed authenticators for
1103 * given user. Clear cached authenticators before validating when requested.
1104 */
1105 private void validateAccountsInternal(
1106 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001107 if (Log.isLoggable(TAG, Log.DEBUG)) {
1108 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001109 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001110 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001111 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001112
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001113 if (invalidateAuthenticatorCache) {
1114 mAuthenticatorCache.invalidateCache(accounts.userId);
1115 }
1116
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001117 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1118 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001119 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001120
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001121 synchronized (accounts.dbLock) {
1122 synchronized (accounts.cacheLock) {
1123 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001124
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001125 // Get a map of stored authenticator types to UID
1126 final AccountsDb accountsDb = accounts.accountsDb;
1127 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1128 // Create a list of authenticator type whose previous uid no longer exists
1129 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1130 SparseBooleanArray knownUids = null;
1131 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1132 String type = authToUidEntry.getKey();
1133 int uid = authToUidEntry.getValue();
1134 Integer knownUid = knownAuth.get(type);
1135 if (knownUid != null && uid == knownUid) {
1136 // Remove it from the knownAuth list if it's unchanged.
1137 knownAuth.remove(type);
1138 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001139 /*
1140 * The authenticator is presently not cached and should only be triggered
1141 * when we think an authenticator has been removed (or is being updated).
1142 * But we still want to check if any data with the associated uid is
1143 * around. This is an (imperfect) signal that the package may be updating.
1144 *
1145 * A side effect of this is that an authenticator sharing a uid with
1146 * multiple apps won't get its credentials wiped as long as some app with
1147 * that uid is still on the device. But I suspect that this is a rare case.
1148 * And it isn't clear to me how an attacker could really exploit that
1149 * feature.
1150 *
1151 * The upshot is that we don't have to worry about accounts getting
1152 * uninstalled while the authenticator's package is being updated.
1153 *
1154 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001155 if (knownUids == null) {
1156 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1157 }
1158 if (!knownUids.get(uid)) {
1159 // The authenticator is not presently available to the cache. And the
1160 // package no longer has a data directory (so we surmise it isn't
1161 // updating). So purge its data from the account databases.
1162 obsoleteAuthType.add(type);
1163 // And delete it from the TABLE_META
1164 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1165 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001166 }
1167 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001168
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001169 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1170 // been re-enabled (after being updated for example), then we just overwrite the old
1171 // values.
1172 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1173 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1174 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001175
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001176 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1177 try {
1178 accounts.accountCache.clear();
1179 final HashMap<String, ArrayList<String>> accountNamesByType
1180 = new LinkedHashMap<>();
1181 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1182 final long accountId = accountEntry.getKey();
1183 final Account account = accountEntry.getValue();
1184 if (obsoleteAuthType.contains(account.type)) {
Hui Yu139c2482018-08-10 15:37:51 -07001185 Slog.w(TAG, "deleting account " + account.toSafeString()
1186 + " because type " + account.type
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001187 + "'s registered authenticator no longer exist.");
1188 Map<String, Integer> packagesToVisibility =
1189 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001190 List<String> accountRemovedReceivers =
1191 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001192 accountsDb.beginTransaction();
1193 try {
1194 accountsDb.deleteDeAccount(accountId);
1195 // Also delete from CE table if user is unlocked; if user is
1196 // currently locked the account will be removed later by
1197 // syncDeCeAccountsLocked
1198 if (userUnlocked) {
1199 accountsDb.deleteCeAccount(accountId);
1200 }
1201 accountsDb.setTransactionSuccessful();
1202 } finally {
1203 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001204 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001205 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001206
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001207 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1208 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001209
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001210 accounts.userDataCache.remove(account);
1211 accounts.authTokenCache.remove(account);
1212 accounts.accountTokenCaches.remove(account);
1213 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001214
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001215 for (Entry<String, Integer> packageToVisibility :
1216 packagesToVisibility.entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -07001217 if (isVisible(packageToVisibility.getValue())) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001218 notifyPackage(packageToVisibility.getKey(), accounts);
1219 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001220 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001221 for (String packageName : accountRemovedReceivers) {
1222 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1223 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001224 } else {
1225 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1226 if (accountNames == null) {
1227 accountNames = new ArrayList<>();
1228 accountNamesByType.put(account.type, accountNames);
1229 }
1230 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001231 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001232 }
1233 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1234 final String accountType = cur.getKey();
1235 final ArrayList<String> accountNames = cur.getValue();
1236 final Account[] accountsForType = new Account[accountNames.size()];
1237 for (int i = 0; i < accountsForType.length; i++) {
1238 accountsForType[i] = new Account(accountNames.get(i), accountType,
1239 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001240 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001241 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001242 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001243 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1244 } finally {
1245 if (accountDeleted) {
1246 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001247 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001248 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001249 }
1250 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001251 }
1252
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001253 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1254 // Get the UIDs of all apps that might have data on the device. We want
1255 // to preserve user data if the app might otherwise be storing data.
1256 List<PackageInfo> pkgsWithData =
1257 mPackageManager.getInstalledPackagesAsUser(
1258 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1259 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1260 for (PackageInfo pkgInfo : pkgsWithData) {
1261 if (pkgInfo.applicationInfo != null
1262 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1263 knownUids.put(pkgInfo.applicationInfo.uid, true);
1264 }
1265 }
1266 return knownUids;
1267 }
1268
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001269 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001270 Context context,
1271 int userId) {
1272 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001273 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1274 }
1275
1276 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1277 IAccountAuthenticatorCache authCache,
1278 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001279 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001280 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1281 .getAllServices(userId)) {
1282 knownAuth.put(service.type.type, service.uid);
1283 }
1284 return knownAuth;
1285 }
1286
Amith Yamasani04e0d262012-02-14 11:50:53 -08001287 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001288 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001289 }
1290
1291 protected UserAccounts getUserAccounts(int userId) {
Felipe Lemebc215de2019-12-05 15:23:16 -08001292 try {
1293 return getUserAccountsNotChecked(userId);
1294 } catch (RuntimeException e) {
1295 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
1296 // Let it go...
1297 throw e;
1298 }
1299 // User accounts database is corrupted, we must wipe out the whole user, otherwise the
1300 // system will crash indefinitely
1301 Slog.wtf(TAG, "Removing user " + userId + " due to exception (" + e + ") reading its "
1302 + "account database");
1303 if (userId == ActivityManager.getCurrentUser() && userId != UserHandle.USER_SYSTEM) {
1304 Slog.i(TAG, "Switching to system user first");
1305 try {
1306 ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
1307 } catch (RemoteException re) {
1308 Slog.e(TAG, "Could not switch to " + UserHandle.USER_SYSTEM + ": " + re);
1309 }
1310 }
1311 if (!getUserManager().removeUserEvenWhenDisallowed(userId)) {
1312 Slog.e(TAG, "could not remove user " + userId);
1313 }
1314 throw e;
1315 }
1316 }
1317
1318 private UserAccounts getUserAccountsNotChecked(int userId) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001319 synchronized (mUsers) {
1320 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001321 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001322 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001323 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1324 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001325 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001326 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001327 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001328 validateAccounts = true;
1329 }
1330 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001331 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001332 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001333 synchronized (accounts.dbLock) {
1334 synchronized (accounts.cacheLock) {
1335 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1336 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1337 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001338 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001339 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001340 }
1341 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001342 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001343 }
1344 return accounts;
1345 }
1346 }
1347
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001348 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1349 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001350 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001351 if (!accountsToRemove.isEmpty()) {
Hui Yu139c2482018-08-10 15:37:51 -07001352 Slog.i(TAG, accountsToRemove.size()
1353 + " accounts were previously deleted while user "
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001354 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001355 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1356 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001357
1358 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001359 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001360 }
1361 }
1362 }
1363
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001364 private void purgeOldGrantsAll() {
1365 synchronized (mUsers) {
1366 for (int i = 0; i < mUsers.size(); i++) {
1367 purgeOldGrants(mUsers.valueAt(i));
1368 }
1369 }
1370 }
1371
1372 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001373 synchronized (accounts.dbLock) {
1374 synchronized (accounts.cacheLock) {
1375 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1376 for (int uid : uids) {
1377 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1378 if (packageExists) {
1379 continue;
1380 }
1381 Log.d(TAG, "deleting grants for UID " + uid
1382 + " because its package is no longer installed");
1383 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001384 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001385 }
1386 }
1387 }
1388
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001389 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001390 if (isSpecialPackageKey(packageName)) {
1391 return;
1392 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001393 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001394 int numberOfUsers = mUsers.size();
1395 for (int i = 0; i < numberOfUsers; i++) {
1396 UserAccounts accounts = mUsers.valueAt(i);
1397 try {
1398 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1399 } catch (NameNotFoundException e) {
1400 // package does not exist - remove visibility values
1401 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001402 synchronized (accounts.dbLock) {
1403 synchronized (accounts.cacheLock) {
1404 for (Account account : accounts.visibilityCache.keySet()) {
1405 Map<String, Integer> accountVisibility =
1406 getPackagesAndVisibilityForAccountLocked(account, accounts);
1407 accountVisibility.remove(packageName);
1408 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001409 }
1410 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001411 }
1412 }
1413 }
1414 }
1415
Fyodor Kupolov945c97e2017-06-21 17:45:19 -07001416 private void purgeUserData(int userId) {
Amith Yamasani13593602012-03-22 16:16:17 -07001417 UserAccounts accounts;
1418 synchronized (mUsers) {
1419 accounts = mUsers.get(userId);
1420 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001421 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001422 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001423 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001424 synchronized (accounts.dbLock) {
1425 synchronized (accounts.cacheLock) {
Dmitry Dementyev47443192018-10-24 13:31:59 -07001426 accounts.accountsDb.closeDebugStatement();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001427 accounts.accountsDb.close();
1428 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001429 }
Amith Yamasani13593602012-03-22 16:16:17 -07001430 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001431 }
1432
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001433 @VisibleForTesting
1434 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001435 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1436 }
1437
1438 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001439 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1440 Log.v(TAG, "onUserUnlocked " + userId);
1441 }
1442 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001443 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001444 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001445 if (userId < 1) return;
Fyodor Kupolov2bc895d2017-12-19 11:53:47 -08001446 mHandler.post(() -> syncSharedAccounts(userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001447 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001448
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001449 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001450 // Check if there's a shared account that needs to be created as an account
1451 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1452 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001453 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001454 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001455 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001456 : UserHandle.USER_SYSTEM;
1457 if (parentUserId < 0) {
1458 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1459 return;
1460 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001461 for (Account sa : sharedAccounts) {
1462 if (ArrayUtils.contains(accounts, sa)) continue;
1463 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001464 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001465 }
1466 }
1467
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001468 @Override
1469 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Dmitry Dementyevc3e913b2019-07-11 11:32:16 -07001470 UserInfo user = getUserManager().getUserInfo(userId);
1471 if (user == null) {
1472 Log.w(TAG, "onServiceChanged: ignore removed user " + userId);
1473 return;
1474 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001475 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001476 }
1477
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001478 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001479 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001480 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001481 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1482 Log.v(TAG, "getPassword: " + account
1483 + ", caller's uid " + Binder.getCallingUid()
1484 + ", pid " + Binder.getCallingPid());
1485 }
Fred Quintana382601f2010-03-25 12:25:10 -07001486 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001487 int userId = UserHandle.getCallingUserId();
1488 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001489 String msg = String.format(
1490 "uid %s cannot get secrets for accounts of type: %s",
1491 callingUid,
1492 account.type);
1493 throw new SecurityException(msg);
1494 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001495 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001496 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001497 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001498 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001499 } finally {
1500 restoreCallingIdentity(identityToken);
1501 }
1502 }
1503
Amith Yamasani04e0d262012-02-14 11:50:53 -08001504 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001505 if (account == null) {
1506 return null;
1507 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001508 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001509 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1510 return null;
1511 }
Fred Quintana31957f12009-10-21 13:43:10 -07001512
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001513 synchronized (accounts.dbLock) {
1514 synchronized (accounts.cacheLock) {
1515 return accounts.accountsDb
1516 .findAccountPasswordByNameAndType(account.name, account.type);
1517 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001518 }
1519 }
1520
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001521 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001522 public String getPreviousName(Account account) {
1523 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1524 Log.v(TAG, "getPreviousName: " + account
1525 + ", caller's uid " + Binder.getCallingUid()
1526 + ", pid " + Binder.getCallingPid());
1527 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00001528 Objects.requireNonNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001529 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001530 long identityToken = clearCallingIdentity();
1531 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001532 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001533 return readPreviousNameInternal(accounts, account);
1534 } finally {
1535 restoreCallingIdentity(identityToken);
1536 }
1537 }
1538
1539 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1540 if (account == null) {
1541 return null;
1542 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001543 synchronized (accounts.dbLock) {
1544 synchronized (accounts.cacheLock) {
1545 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1546 if (previousNameRef == null) {
1547 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1548 previousNameRef = new AtomicReference<>(previousName);
1549 accounts.previousNameCache.put(account, previousNameRef);
1550 return previousName;
1551 } else {
1552 return previousNameRef.get();
1553 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001554 }
1555 }
1556 }
1557
1558 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001559 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001560 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001561 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001562 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1563 account, key, callingUid, Binder.getCallingPid());
1564 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001565 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00001566 Objects.requireNonNull(account, "account cannot be null");
1567 Objects.requireNonNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001568 int userId = UserHandle.getCallingUserId();
1569 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001570 String msg = String.format(
1571 "uid %s cannot get user data for accounts of type: %s",
1572 callingUid,
1573 account.type);
1574 throw new SecurityException(msg);
1575 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001576 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001577 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1578 return null;
1579 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001580 long identityToken = clearCallingIdentity();
1581 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001582 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001583 if (!accountExistsCache(accounts, account)) {
1584 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001585 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001586 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001587 } finally {
1588 restoreCallingIdentity(identityToken);
1589 }
1590 }
1591
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001592 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001593 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001594 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001595 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1596 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001597 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001598 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001599 + ", pid " + Binder.getCallingPid());
1600 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001601 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001602 if (isCrossUser(callingUid, userId)) {
1603 throw new SecurityException(
1604 String.format(
1605 "User %s tying to get authenticator types for %s" ,
1606 UserHandle.getCallingUserId(),
1607 userId));
1608 }
1609
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001610 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001611 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001612 return getAuthenticatorTypesInternal(userId);
1613
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001614 } finally {
1615 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001616 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001617 }
1618
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001619 /**
1620 * Should only be called inside of a clearCallingIdentity block.
1621 */
1622 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001623 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001624 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1625 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1626 AuthenticatorDescription[] types =
1627 new AuthenticatorDescription[authenticatorCollection.size()];
1628 int i = 0;
1629 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1630 : authenticatorCollection) {
1631 types[i] = authenticator.type;
1632 i++;
1633 }
1634 return types;
1635 }
1636
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001637 private boolean isCrossUser(int callingUid, int userId) {
1638 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001639 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001640 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001641 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1642 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001643 }
1644
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001645 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001646 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001647 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001648 }
1649
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001650 @Override
1651 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001652 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001653 int callingUid = Binder.getCallingUid();
1654 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1655 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001656 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001657 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001658 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1659 final UserAccounts toAccounts = getUserAccounts(userTo);
1660 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001661 if (response != null) {
1662 Bundle result = new Bundle();
1663 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1664 try {
1665 response.onResult(result);
1666 } catch (RemoteException e) {
1667 Slog.w(TAG, "Failed to report error back to the client." + e);
1668 }
1669 }
1670 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001671 }
1672
Hui Yu139c2482018-08-10 15:37:51 -07001673 Slog.d(TAG, "Copying account " + account.toSafeString()
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001674 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001675 long identityToken = clearCallingIdentity();
1676 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001677 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001678 false /* stripAuthTokenFromResult */, account.name,
1679 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001680 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001681 protected String toDebugString(long now) {
1682 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1683 + ", " + account.type;
1684 }
1685
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001686 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001687 public void run() throws RemoteException {
1688 mAuthenticator.getAccountCredentialsForCloning(this, account);
1689 }
1690
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001691 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001692 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001693 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001694 if (result != null
1695 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1696 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001697 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001698 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001699 super.onResult(result);
1700 }
1701 }
1702 }.bind();
1703 } finally {
1704 restoreCallingIdentity(identityToken);
1705 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001706 }
1707
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001708 @Override
1709 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001710 final int callingUid = Binder.getCallingUid();
1711 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1712 String msg = String.format(
1713 "accountAuthenticated( account: %s, callerUid: %s)",
1714 account,
1715 callingUid);
1716 Log.v(TAG, msg);
1717 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00001718 Objects.requireNonNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001719 int userId = UserHandle.getCallingUserId();
1720 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001721 String msg = String.format(
1722 "uid %s cannot notify authentication for accounts of type: %s",
1723 callingUid,
1724 account.type);
1725 throw new SecurityException(msg);
1726 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001727
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001728 if (!canUserModifyAccounts(userId, callingUid) ||
1729 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001730 return false;
1731 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001732
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001733 long identityToken = clearCallingIdentity();
1734 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001735 UserAccounts accounts = getUserAccounts(userId);
1736 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001737 } finally {
1738 restoreCallingIdentity(identityToken);
1739 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001740 }
1741
1742 private boolean updateLastAuthenticatedTime(Account account) {
1743 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001744 synchronized (accounts.dbLock) {
1745 synchronized (accounts.cacheLock) {
1746 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1747 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001748 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001749 }
1750
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001751 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001752 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1753 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001754 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001755 long id = clearCallingIdentity();
1756 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001757 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001758 false /* stripAuthTokenFromResult */, account.name,
1759 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001760 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001761 protected String toDebugString(long now) {
1762 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1763 + ", " + account.type;
1764 }
1765
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001766 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001767 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001768 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001769 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1770 if (acc.equals(account)) {
1771 mAuthenticator.addAccountFromCredentials(
1772 this, account, accountCredentials);
1773 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001774 }
1775 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001776 }
1777
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001778 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001779 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001780 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001781 // TODO: Anything to do if if succedded?
1782 // TODO: If it failed: Show error notification? Should we remove the shadow
1783 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001784 // TODO: what we do with the visibility?
1785
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001786 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001787 }
1788
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001789 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001790 public void onError(int errorCode, String errorMessage) {
1791 super.onError(errorCode, errorMessage);
1792 // TODO: Show error notification to user
1793 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1794 }
1795
1796 }.bind();
1797 } finally {
1798 restoreCallingIdentity(id);
1799 }
1800 }
1801
Amith Yamasani04e0d262012-02-14 11:50:53 -08001802 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001803 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001804 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001805 if (account == null) {
1806 return false;
1807 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001808 if (!isLocalUnlockedUser(accounts.userId)) {
Hui Yu139c2482018-08-10 15:37:51 -07001809 Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
1810 + accounts.userId + " is locked. callingUid=" + callingUid);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001811 return false;
1812 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001813 synchronized (accounts.dbLock) {
1814 synchronized (accounts.cacheLock) {
1815 accounts.accountsDb.beginTransaction();
1816 try {
1817 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001818 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001819 + ", skipping since the account already exists");
1820 return false;
1821 }
1822 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1823 if (accountId < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001824 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001825 + ", skipping the DB insert failed");
1826 return false;
1827 }
1828 // Insert into DE table
1829 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001830 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001831 + ", skipping the DB insert failed");
1832 return false;
1833 }
1834 if (extras != null) {
1835 for (String key : extras.keySet()) {
1836 final String value = extras.getString(key);
1837 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001838 Log.w(TAG, "insertAccountIntoDatabase: "
1839 + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001840 + ", skipping since insertExtra failed for key " + key);
1841 return false;
1842 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001843 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001844 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001845
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001846 if (packageToVisibility != null) {
1847 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1848 setAccountVisibility(account, entry.getKey() /* package */,
1849 entry.getValue() /* visibility */, false /* notify */,
1850 accounts);
1851 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001852 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001853 accounts.accountsDb.setTransactionSuccessful();
1854
1855 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1856 accountId,
1857 accounts, callingUid);
1858
1859 insertAccountIntoCacheLocked(accounts, account);
1860 } finally {
1861 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001862 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001863 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001864 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001865 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1866 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001867 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001868
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001869 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001870 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1871 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001872
Amith Yamasani5be347b2013-03-31 17:44:31 -07001873 return true;
1874 }
1875
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001876 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001877 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001878 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001879 }
1880 }
1881
Amith Yamasani5be347b2013-03-31 17:44:31 -07001882 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001883 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001884 * running, then clone the account too.
1885 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001886 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001887 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001888 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001889 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001890 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001891 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001892 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001893 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001894 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001895 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001896 }
1897 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001898 }
1899 }
1900
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001901 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001902 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001903 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001904 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001905 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001906 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1907 Log.v(TAG, "hasFeatures: " + account
1908 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001909 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001910 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001911 + ", pid " + Binder.getCallingPid());
1912 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001913 Preconditions.checkArgument(account != null, "account cannot be null");
1914 Preconditions.checkArgument(response != null, "response cannot be null");
1915 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001916 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001917 checkReadAccountsPermitted(callingUid, account.type, userId,
1918 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001919
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001920 long identityToken = clearCallingIdentity();
1921 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001922 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001923 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001924 } finally {
1925 restoreCallingIdentity(identityToken);
1926 }
1927 }
1928
1929 private class TestFeaturesSession extends Session {
1930 private final String[] mFeatures;
1931 private final Account mAccount;
1932
Amith Yamasani04e0d262012-02-14 11:50:53 -08001933 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001934 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001935 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001936 true /* stripAuthTokenFromResult */, account.name,
1937 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001938 mFeatures = features;
1939 mAccount = account;
1940 }
1941
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001942 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001943 public void run() throws RemoteException {
1944 try {
1945 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1946 } catch (RemoteException e) {
1947 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1948 }
1949 }
1950
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001951 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001952 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001953 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001954 IAccountManagerResponse response = getResponseAndClose();
1955 if (response != null) {
1956 try {
1957 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001958 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001959 return;
1960 }
Fred Quintana56285a62010-12-02 14:20:51 -08001961 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1962 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1963 + response);
1964 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001965 final Bundle newResult = new Bundle();
1966 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1967 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1968 response.onResult(newResult);
1969 } catch (RemoteException e) {
1970 // if the caller is dead then there is no one to care about remote exceptions
1971 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1972 Log.v(TAG, "failure while notifying response", e);
1973 }
1974 }
1975 }
1976 }
1977
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001978 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001979 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001980 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001981 + ", " + mAccount
1982 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1983 }
1984 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001985
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001986 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001987 public void renameAccount(
1988 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001989 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001990 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1991 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001992 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001993 + ", pid " + Binder.getCallingPid());
1994 }
1995 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001996 int userId = UserHandle.getCallingUserId();
1997 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001998 String msg = String.format(
1999 "uid %s cannot rename accounts of type: %s",
2000 callingUid,
2001 accountToRename.type);
2002 throw new SecurityException(msg);
2003 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002004 long identityToken = clearCallingIdentity();
2005 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002006 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002007 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002008 Bundle result = new Bundle();
2009 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
2010 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07002011 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
2012 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002013 try {
2014 response.onResult(result);
2015 } catch (RemoteException e) {
2016 Log.w(TAG, e.getMessage());
2017 }
2018 } finally {
2019 restoreCallingIdentity(identityToken);
2020 }
2021 }
2022
2023 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002024 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002025 Account resultAccount = null;
2026 /*
2027 * Cancel existing notifications. Let authenticators
2028 * re-post notifications as required. But we don't know if
2029 * the authenticators have bound their notifications to
2030 * now stale account name data.
2031 *
2032 * With a rename api, we might not need to do this anymore but it
2033 * shouldn't hurt.
2034 */
2035 cancelNotification(
2036 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04002037 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002038 synchronized(accounts.credentialsPermissionNotificationIds) {
2039 for (Pair<Pair<Account, String>, Integer> pair:
2040 accounts.credentialsPermissionNotificationIds.keySet()) {
2041 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002042 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002043 cancelNotification(id, new UserHandle(accounts.userId));
2044 }
2045 }
2046 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002047 synchronized (accounts.dbLock) {
2048 synchronized (accounts.cacheLock) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002049 List<String> accountRemovedReceivers =
2050 getAccountRemovedReceivers(accountToRename, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002051 accounts.accountsDb.beginTransaction();
2052 Account renamedAccount = new Account(newName, accountToRename.type);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002053 try {
chengangf2d081c2017-12-27 17:17:32 +08002054 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
2055 Log.e(TAG, "renameAccount failed - account with new name already exists");
2056 return null;
2057 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002058 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2059 if (accountId >= 0) {
2060 accounts.accountsDb.renameCeAccount(accountId, newName);
2061 if (accounts.accountsDb.renameDeAccount(
2062 accountId, newName, accountToRename.name)) {
2063 accounts.accountsDb.setTransactionSuccessful();
2064 } else {
2065 Log.e(TAG, "renameAccount failed");
2066 return null;
2067 }
2068 } else {
2069 Log.e(TAG, "renameAccount failed - old account does not exist");
2070 return null;
2071 }
2072 } finally {
2073 accounts.accountsDb.endTransaction();
2074 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002075 /*
2076 * Database transaction was successful. Clean up cached
2077 * data associated with the account in the user profile.
2078 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002079 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002080 /*
2081 * Extract the data and token caches before removing the
2082 * old account to preserve the user data associated with
2083 * the account.
2084 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002085 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2086 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2087 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2088 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002089 /*
2090 * Update the cached data associated with the renamed
2091 * account.
2092 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002093 accounts.userDataCache.put(renamedAccount, tmpData);
2094 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2095 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2096 accounts.previousNameCache.put(
2097 renamedAccount,
2098 new AtomicReference<>(accountToRename.name));
2099 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002100
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002101 int parentUserId = accounts.userId;
2102 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002103 /*
2104 * Owner or system user account was renamed, rename the account for
2105 * those users with which the account was shared.
2106 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002107 List<UserInfo> users = getUserManager().getUsers(true);
2108 for (UserInfo user : users) {
2109 if (user.isRestricted()
2110 && (user.restrictedProfileParentId == parentUserId)) {
2111 renameSharedAccountAsUser(accountToRename, newName, user.id);
2112 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002113 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002114 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002115
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002116 sendNotificationAccountUpdated(resultAccount, accounts);
2117 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002118 for (String packageName : accountRemovedReceivers) {
2119 sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2120 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002121 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002122 }
2123 return resultAccount;
2124 }
2125
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002126 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002127 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002128 return userInfo != null && userInfo.canHaveProfile();
2129 }
2130
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002131 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002132 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002133 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002134 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002135 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2136 Log.v(TAG, "removeAccount: " + account
2137 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002138 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002139 + ", pid " + Binder.getCallingPid()
2140 + ", for user id " + userId);
2141 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002142 Preconditions.checkArgument(account != null, "account cannot be null");
2143 Preconditions.checkArgument(response != null, "response cannot be null");
2144
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002145 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002146 if (isCrossUser(callingUid, userId)) {
2147 throw new SecurityException(
2148 String.format(
2149 "User %s tying remove account for %s" ,
2150 UserHandle.getCallingUserId(),
2151 userId));
2152 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002153 /*
Alex Chauf788f9c2017-12-08 15:16:46 +00002154 * Only the system, authenticator or profile owner should be allowed to remove accounts for
2155 * that authenticator. This will let users remove accounts (via Settings in the system) but
2156 * not arbitrary applications (like competing authenticators).
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002157 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002158 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002159 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
Alex Chauf788f9c2017-12-08 15:16:46 +00002160 && !isSystemUid(callingUid)
2161 && !isProfileOwner(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002162 String msg = String.format(
2163 "uid %s cannot remove accounts of type: %s",
2164 callingUid,
2165 account.type);
2166 throw new SecurityException(msg);
2167 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002168 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002169 try {
2170 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2171 "User cannot modify accounts");
2172 } catch (RemoteException re) {
2173 }
2174 return;
2175 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002176 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002177 try {
2178 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2179 "User cannot modify accounts of this type (policy).");
2180 } catch (RemoteException re) {
2181 }
2182 return;
2183 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002184 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002185 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002186 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002187 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002188 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002189 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002190 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002191 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002192 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002193 }
2194 }
2195 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002196 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002197 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002198 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2199 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002200 accountId,
2201 accounts,
2202 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002203 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002204 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2205 } finally {
2206 restoreCallingIdentity(identityToken);
2207 }
2208 }
2209
2210 @Override
2211 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002212 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002213 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2214 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002215 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002216 + ", pid " + Binder.getCallingPid());
2217 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002218 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002219 if (account == null) {
2220 /*
2221 * Null accounts should result in returning false, as per
2222 * AccountManage.addAccountExplicitly(...) java doc.
2223 */
2224 Log.e(TAG, "account is null");
2225 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002226 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002227 String msg = String.format(
Brandon Weeks9e4e96d2017-08-24 15:24:16 -07002228 "uid %s cannot explicitly remove accounts of type: %s",
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002229 callingUid,
2230 account.type);
2231 throw new SecurityException(msg);
2232 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002233 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002234 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002235 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002236 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2237 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002238 accountId,
2239 accounts,
2240 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002241 long identityToken = clearCallingIdentity();
2242 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002243 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002244 } finally {
2245 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002246 }
Fred Quintana60307342009-03-24 22:48:12 -07002247 }
2248
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002249 private class RemoveAccountSession extends Session {
2250 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002251 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002252 Account account, boolean expectActivityLaunch) {
2253 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002254 true /* stripAuthTokenFromResult */, account.name,
2255 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002256 mAccount = account;
2257 }
2258
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002259 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002260 protected String toDebugString(long now) {
2261 return super.toDebugString(now) + ", removeAccount"
2262 + ", account " + mAccount;
2263 }
2264
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002265 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002266 public void run() throws RemoteException {
2267 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2268 }
2269
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002270 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002271 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002272 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002273 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2274 && !result.containsKey(AccountManager.KEY_INTENT)) {
2275 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002276 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002277 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002278 }
2279 IAccountManagerResponse response = getResponseAndClose();
2280 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002281 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2282 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2283 + response);
2284 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002285 try {
tiansiming5330b5a2017-10-13 10:57:25 +08002286 response.onResult(result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002287 } catch (RemoteException e) {
tiansiming5330b5a2017-10-13 10:57:25 +08002288 Slog.e(TAG, "Error calling onResult()", e);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002289 }
2290 }
2291 }
2292 super.onResult(result);
2293 }
2294 }
2295
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002296 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002297 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002298 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002299 }
2300
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002301 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002302 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002303 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002304 if (!userUnlocked) {
Hui Yu139c2482018-08-10 15:37:51 -07002305 Slog.i(TAG, "Removing account " + account.toSafeString()
2306 + " while user " + accounts.userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002307 + " is still locked. CE data will be removed later");
2308 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002309 synchronized (accounts.dbLock) {
2310 synchronized (accounts.cacheLock) {
2311 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2312 accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002313 List<String> accountRemovedReceivers =
2314 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002315 accounts.accountsDb.beginTransaction();
2316 // Set to a dummy value, this will only be used if the database
2317 // transaction succeeds.
2318 long accountId = -1;
2319 try {
2320 accountId = accounts.accountsDb.findDeAccountId(account);
2321 if (accountId >= 0) {
2322 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002323 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002324 // always delete from CE table if CE storage is available
2325 // DE account could be removed while CE was locked
2326 if (userUnlocked) {
2327 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2328 if (ceAccountId >= 0) {
2329 accounts.accountsDb.deleteCeAccount(ceAccountId);
2330 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002331 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002332 accounts.accountsDb.setTransactionSuccessful();
2333 } finally {
2334 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002335 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002336 if (isChanged) {
2337 removeAccountFromCacheLocked(accounts, account);
2338 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2339 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002340 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2341 || (packageToVisibility.getValue()
2342 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002343 notifyPackage(packageToVisibility.getKey(), accounts);
2344 }
2345 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002346
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002347 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2348 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002349 for (String packageName : accountRemovedReceivers) {
2350 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2351 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002352 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2353 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2354 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2355 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002356 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002357 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002358 long id = Binder.clearCallingIdentity();
2359 try {
2360 int parentUserId = accounts.userId;
2361 if (canHaveProfile(parentUserId)) {
2362 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002363 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002364 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002365 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002366 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002367 }
2368 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002369 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002370 } finally {
2371 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002372 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002373
2374 if (isChanged) {
2375 synchronized (accounts.credentialsPermissionNotificationIds) {
2376 for (Pair<Pair<Account, String>, Integer> key
2377 : accounts.credentialsPermissionNotificationIds.keySet()) {
2378 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002379 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002380 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002381 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002382 account, uid, false));
2383 }
2384 }
2385 }
2386 }
2387
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002388 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002389 }
2390
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002391 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002392 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002393 int callerUid = Binder.getCallingUid();
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00002394 Objects.requireNonNull(accountType, "accountType cannot be null");
2395 Objects.requireNonNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002396 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2397 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002398 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002399 + ", pid " + Binder.getCallingPid());
2400 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002401 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002402 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002403 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002404 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002405 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002406 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002407 accounts.accountsDb.beginTransaction();
2408 try {
2409 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2410 accounts.accountsDb.setTransactionSuccessful();
2411 } finally {
2412 accounts.accountsDb.endTransaction();
2413 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002414 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002415 for (Pair<Account, String> tokenInfo : deletedTokens) {
2416 Account act = tokenInfo.first;
2417 String tokenType = tokenInfo.second;
2418 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002419 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002420 // wipe out cached token in memory.
2421 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002422 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002423 }
Fred Quintana60307342009-03-24 22:48:12 -07002424 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002425 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002426 }
2427 }
2428
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002429 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002430 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002431 // TODO Move to AccountsDB
2432 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002433 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002434
Fred Quintana33269202009-04-20 16:05:10 -07002435 try {
2436 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002437 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002438 String accountName = cursor.getString(1);
2439 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002440 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002441 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002442 }
Fred Quintana33269202009-04-20 16:05:10 -07002443 } finally {
2444 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002445 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002446 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002447 }
2448
Carlos Valdivia91979be2015-05-22 14:11:35 -07002449 private void saveCachedToken(
2450 UserAccounts accounts,
2451 Account account,
2452 String callerPkg,
2453 byte[] callerSigDigest,
2454 String tokenType,
2455 String token,
2456 long expiryMillis) {
2457
2458 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2459 return;
2460 }
2461 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002462 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002463 synchronized (accounts.cacheLock) {
2464 accounts.accountTokenCaches.put(
2465 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002466 }
2467 }
2468
Amith Yamasani04e0d262012-02-14 11:50:53 -08002469 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2470 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002471 if (account == null || type == null) {
2472 return false;
2473 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002474 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002475 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002476 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002477 accounts.accountsDb.beginTransaction();
2478 boolean updateCache = false;
2479 try {
2480 long accountId = accounts.accountsDb.findDeAccountId(account);
2481 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002482 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002483 }
2484 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2485 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2486 accounts.accountsDb.setTransactionSuccessful();
2487 updateCache = true;
2488 return true;
2489 }
2490 return false;
2491 } finally {
2492 accounts.accountsDb.endTransaction();
2493 if (updateCache) {
2494 synchronized (accounts.cacheLock) {
2495 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2496 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002497 }
Fred Quintana33269202009-04-20 16:05:10 -07002498 }
Fred Quintana60307342009-03-24 22:48:12 -07002499 }
2500 }
2501
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002502 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002503 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002504 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002505 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2506 Log.v(TAG, "peekAuthToken: " + account
2507 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002508 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002509 + ", pid " + Binder.getCallingPid());
2510 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00002511 Objects.requireNonNull(account, "account cannot be null");
2512 Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002513 int userId = UserHandle.getCallingUserId();
2514 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002515 String msg = String.format(
2516 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2517 callingUid,
2518 account.type);
2519 throw new SecurityException(msg);
2520 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002521 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002522 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2523 + callingUid);
2524 return null;
2525 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002526 long identityToken = clearCallingIdentity();
2527 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002528 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002529 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002530 } finally {
2531 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002532 }
Fred Quintana60307342009-03-24 22:48:12 -07002533 }
2534
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002535 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002536 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002537 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002538 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2539 Log.v(TAG, "setAuthToken: " + account
2540 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002541 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002542 + ", pid " + Binder.getCallingPid());
2543 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00002544 Objects.requireNonNull(account, "account cannot be null");
2545 Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002546 int userId = UserHandle.getCallingUserId();
2547 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002548 String msg = String.format(
2549 "uid %s cannot set auth tokens associated with accounts of type: %s",
2550 callingUid,
2551 account.type);
2552 throw new SecurityException(msg);
2553 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002554 long identityToken = clearCallingIdentity();
2555 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002556 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002557 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002558 } finally {
2559 restoreCallingIdentity(identityToken);
2560 }
Fred Quintana60307342009-03-24 22:48:12 -07002561 }
2562
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002563 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002564 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002565 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002566 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2567 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002568 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002569 + ", pid " + Binder.getCallingPid());
2570 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00002571 Objects.requireNonNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002572 int userId = UserHandle.getCallingUserId();
2573 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002574 String msg = String.format(
2575 "uid %s cannot set secrets for accounts of type: %s",
2576 callingUid,
2577 account.type);
2578 throw new SecurityException(msg);
2579 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002580 long identityToken = clearCallingIdentity();
2581 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002582 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002583 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002584 } finally {
2585 restoreCallingIdentity(identityToken);
2586 }
Fred Quintana60307342009-03-24 22:48:12 -07002587 }
2588
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002589 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2590 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002591 if (account == null) {
2592 return;
2593 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002594 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002595 synchronized (accounts.dbLock) {
2596 synchronized (accounts.cacheLock) {
2597 accounts.accountsDb.beginTransaction();
2598 try {
2599 final long accountId = accounts.accountsDb.findDeAccountId(account);
2600 if (accountId >= 0) {
2601 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2602 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2603 accounts.authTokenCache.remove(account);
2604 accounts.accountTokenCaches.remove(account);
2605 accounts.accountsDb.setTransactionSuccessful();
2606 // If there is an account whose password will be updated and the database
2607 // transactions succeed, then we say that a change has occured. Even if the
2608 // new password is the same as the old and there were no authtokens to
2609 // delete.
2610 isChanged = true;
2611 String action = (password == null || password.length() == 0) ?
2612 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2613 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2614 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2615 callingUid);
2616 }
2617 } finally {
2618 accounts.accountsDb.endTransaction();
2619 if (isChanged) {
2620 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2621 sendNotificationAccountUpdated(account, accounts);
2622 sendAccountsChangedBroadcast(accounts.userId);
2623 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002624 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002625 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002626 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002627 }
2628
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002629 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002630 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002631 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002632 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2633 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002634 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002635 + ", pid " + Binder.getCallingPid());
2636 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00002637 Objects.requireNonNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002638 int userId = UserHandle.getCallingUserId();
2639 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002640 String msg = String.format(
2641 "uid %s cannot clear passwords for accounts of type: %s",
2642 callingUid,
2643 account.type);
2644 throw new SecurityException(msg);
2645 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002646 long identityToken = clearCallingIdentity();
2647 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002648 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002649 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002650 } finally {
2651 restoreCallingIdentity(identityToken);
2652 }
Fred Quintana60307342009-03-24 22:48:12 -07002653 }
2654
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002655 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002656 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002657 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002658 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2659 Log.v(TAG, "setUserData: " + account
2660 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002661 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002662 + ", pid " + Binder.getCallingPid());
2663 }
Fred Quintana382601f2010-03-25 12:25:10 -07002664 if (key == null) throw new IllegalArgumentException("key is null");
2665 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002666 int userId = UserHandle.getCallingUserId();
2667 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002668 String msg = String.format(
2669 "uid %s cannot set user data for accounts of type: %s",
2670 callingUid,
2671 account.type);
2672 throw new SecurityException(msg);
2673 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002674 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002675 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002676 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002677 if (!accountExistsCache(accounts, account)) {
2678 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002679 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002680 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002681 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002682 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002683 }
2684 }
2685
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002686 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2687 synchronized (accounts.cacheLock) {
2688 if (accounts.accountCache.containsKey(account.type)) {
2689 for (Account acc : accounts.accountCache.get(account.type)) {
2690 if (acc.name.equals(account.name)) {
2691 return true;
2692 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002693 }
2694 }
2695 }
2696 return false;
2697 }
2698
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002699 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002700 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002701 synchronized (accounts.dbLock) {
2702 accounts.accountsDb.beginTransaction();
2703 try {
2704 long accountId = accounts.accountsDb.findDeAccountId(account);
2705 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002706 return;
2707 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002708 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2709 if (extrasId < 0) {
2710 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2711 if (extrasId < 0) {
2712 return;
2713 }
2714 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2715 return;
2716 }
2717 accounts.accountsDb.setTransactionSuccessful();
2718 } finally {
2719 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002720 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002721 synchronized (accounts.cacheLock) {
2722 writeUserDataIntoCacheLocked(accounts, account, key, value);
2723 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002724 }
2725 }
2726
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002727 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002728 if (result == null) {
2729 Log.e(TAG, "the result is unexpectedly null", new Exception());
2730 }
2731 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2732 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2733 + response);
2734 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002735 try {
2736 response.onResult(result);
2737 } catch (RemoteException e) {
2738 // if the caller is dead then there is no one to care about remote
2739 // exceptions
2740 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2741 Log.v(TAG, "failure while notifying response", e);
2742 }
2743 }
2744 }
2745
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002746 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002747 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2748 final String authTokenType)
2749 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002750 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2751 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002752
Fred Quintanad9640ec2012-05-23 12:37:00 -07002753 final int callingUid = getCallingUid();
2754 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002755 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002756 throw new SecurityException("can only call from system");
2757 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002758 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002759 long identityToken = clearCallingIdentity();
2760 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002761 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002762 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2763 false /* stripAuthTokenFromResult */, null /* accountName */,
2764 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002765 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002766 protected String toDebugString(long now) {
2767 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002768 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002769 + ", authTokenType " + authTokenType;
2770 }
2771
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002772 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002773 public void run() throws RemoteException {
2774 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2775 }
2776
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002777 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002778 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002779 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002780 if (result != null) {
2781 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2782 Bundle bundle = new Bundle();
2783 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2784 super.onResult(bundle);
2785 return;
2786 } else {
2787 super.onResult(result);
2788 }
2789 }
2790 }.bind();
2791 } finally {
2792 restoreCallingIdentity(identityToken);
2793 }
2794 }
2795
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002796 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002797 public void getAuthToken(
2798 IAccountManagerResponse response,
2799 final Account account,
2800 final String authTokenType,
2801 final boolean notifyOnAuthFailure,
2802 final boolean expectActivityLaunch,
2803 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002804 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002805 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2806 Log.v(TAG, "getAuthToken: " + account
2807 + ", response " + response
2808 + ", authTokenType " + authTokenType
2809 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2810 + ", expectActivityLaunch " + expectActivityLaunch
2811 + ", caller's uid " + Binder.getCallingUid()
2812 + ", pid " + Binder.getCallingPid());
2813 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002814 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002815 try {
2816 if (account == null) {
2817 Slog.w(TAG, "getAuthToken called with null account");
2818 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2819 return;
2820 }
2821 if (authTokenType == null) {
2822 Slog.w(TAG, "getAuthToken called with null authTokenType");
2823 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2824 return;
2825 }
2826 } catch (RemoteException e) {
2827 Slog.w(TAG, "Failed to report error back to the client." + e);
2828 return;
2829 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002830 int userId = UserHandle.getCallingUserId();
2831 long ident = Binder.clearCallingIdentity();
2832 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002833 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002834 try {
2835 accounts = getUserAccounts(userId);
2836 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2837 AuthenticatorDescription.newKey(account.type), accounts.userId);
2838 } finally {
2839 Binder.restoreCallingIdentity(ident);
2840 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002841
Costin Manolachea40c6302010-12-13 14:50:45 -08002842 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002843 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002844
2845 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002846 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002847 final boolean permissionGranted =
2848 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002849
Carlos Valdivia91979be2015-05-22 14:11:35 -07002850 // Get the calling package. We will use it for the purpose of caching.
2851 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002852 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002853 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002854 try {
2855 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2856 } finally {
2857 Binder.restoreCallingIdentity(ident);
2858 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002859 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2860 String msg = String.format(
2861 "Uid %s is attempting to illegally masquerade as package %s!",
2862 callerUid,
2863 callerPkg);
2864 throw new SecurityException(msg);
2865 }
2866
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002867 // let authenticator know the identity of the caller
2868 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2869 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002870
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002871 if (notifyOnAuthFailure) {
2872 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002873 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002874
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002875 long identityToken = clearCallingIdentity();
2876 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002877 // Distill the caller's package signatures into a single digest.
2878 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2879
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002880 // if the caller has permission, do the peek. otherwise go the more expensive
2881 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002882 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002883 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002884 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002885 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002886 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2887 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2888 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002889 onResult(response, result);
2890 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002891 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002892 }
2893
Carlos Valdivia91979be2015-05-22 14:11:35 -07002894 if (customTokens) {
2895 /*
2896 * Look up tokens in the new cache only if the loginOptions don't have parameters
2897 * outside of those expected to be injected by the AccountManager, e.g.
2898 * ANDORID_PACKAGE_NAME.
2899 */
2900 String token = readCachedTokenInternal(
2901 accounts,
2902 account,
2903 authTokenType,
2904 callerPkg,
2905 callerPkgSigDigest);
2906 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002907 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2908 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2909 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002910 Bundle result = new Bundle();
2911 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2912 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2913 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2914 onResult(response, result);
2915 return;
2916 }
2917 }
2918
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002919 new Session(
2920 accounts,
2921 response,
2922 account.type,
2923 expectActivityLaunch,
2924 false /* stripAuthTokenFromResult */,
2925 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002926 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002927 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002928 protected String toDebugString(long now) {
2929 if (loginOptions != null) loginOptions.keySet();
2930 return super.toDebugString(now) + ", getAuthToken"
Hui Yu139c2482018-08-10 15:37:51 -07002931 + ", " + account.toSafeString()
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002932 + ", authTokenType " + authTokenType
2933 + ", loginOptions " + loginOptions
2934 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2935 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002936
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002937 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002938 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002939 // If the caller doesn't have permission then create and return the
2940 // "grant permission" intent instead of the "getAuthToken" intent.
2941 if (!permissionGranted) {
2942 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2943 } else {
2944 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2945 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002946 }
2947
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002948 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002949 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002950 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002951 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002952 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002953 Intent intent = newGrantCredentialsPermissionIntent(
2954 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002955 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002956 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002957 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002958 authTokenType,
2959 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002960 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002961 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002962 onResult(bundle);
2963 return;
2964 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002965 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002966 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002967 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2968 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002969 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002970 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002971 "the type and name should not be empty");
2972 return;
2973 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002974 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002975 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002976 saveAuthTokenToDatabase(
2977 mAccounts,
2978 resultAccount,
2979 authTokenType,
2980 authToken);
2981 }
2982 long expiryMillis = result.getLong(
2983 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2984 if (customTokens
2985 && expiryMillis > System.currentTimeMillis()) {
2986 saveCachedToken(
2987 mAccounts,
2988 account,
2989 callerPkg,
2990 callerPkgSigDigest,
2991 authTokenType,
2992 authToken,
2993 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002994 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002995 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002996
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002997 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002998 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002999 /*
3000 * Make sure that the supplied intent is owned by the authenticator
3001 * giving it to the system. Otherwise a malicious authenticator could
3002 * have users launching arbitrary activities by tricking users to
3003 * interact with malicious notifications.
3004 */
tiansiminga8868bf2017-09-20 13:59:13 +08003005 if (!checkKeyIntent(
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07003006 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08003007 intent)) {
3008 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3009 "invalid intent in bundle returned");
3010 return;
3011 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003012 doNotification(
3013 mAccounts,
3014 account,
3015 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003016 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003017 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003018 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003019 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07003020 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003021 }.bind();
3022 } finally {
3023 restoreCallingIdentity(identityToken);
3024 }
Fred Quintana60307342009-03-24 22:48:12 -07003025 }
3026
Carlos Valdivia91979be2015-05-22 14:11:35 -07003027 private byte[] calculatePackageSignatureDigest(String callerPkg) {
3028 MessageDigest digester;
3029 try {
3030 digester = MessageDigest.getInstance("SHA-256");
3031 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
3032 callerPkg, PackageManager.GET_SIGNATURES);
3033 for (Signature sig : pkgInfo.signatures) {
3034 digester.update(sig.toByteArray());
3035 }
3036 } catch (NoSuchAlgorithmException x) {
3037 Log.wtf(TAG, "SHA-256 should be available", x);
3038 digester = null;
3039 } catch (NameNotFoundException e) {
3040 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
3041 digester = null;
3042 }
3043 return (digester == null) ? null : digester.digest();
3044 }
3045
Dianne Hackborn41203752012-08-31 14:05:51 -07003046 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003047 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003048 int uid = intent.getIntExtra(
3049 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3050 String authTokenType = intent.getStringExtra(
3051 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07003052 final String titleAndSubtitle =
3053 mContext.getString(R.string.permission_request_notification_with_subtitle,
3054 account.name);
3055 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07003056 String title = titleAndSubtitle;
3057 String subtitle = "";
3058 if (index > 0) {
3059 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04003060 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07003061 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07003062 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003063 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003064 Notification n =
3065 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3066 .setSmallIcon(android.R.drawable.stat_sys_warning)
3067 .setWhen(0)
3068 .setColor(contextForUser.getColor(
3069 com.android.internal.R.color.system_notification_accent_color))
3070 .setContentTitle(title)
3071 .setContentText(subtitle)
3072 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3073 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
3074 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003075 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003076 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003077 }
3078
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003079 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3080 int uid, AccountAuthenticatorResponse response, String authTokenType,
3081 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003082
3083 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003084
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003085 if (startInNewTask) {
3086 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3087 // Since it was set in Eclair+ we can't change it without breaking apps using
3088 // the intent from a non-Activity context. This is the default behavior.
3089 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3090 }
Chris Wren717a8812017-03-31 15:34:39 -04003091 intent.addCategory(getCredentialPermissionNotificationId(account,
3092 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003093 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003094 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3095 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003096 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003097
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003098 return intent;
3099 }
3100
Chris Wren717a8812017-03-31 15:34:39 -04003101 private NotificationId getCredentialPermissionNotificationId(Account account,
3102 String authTokenType, int uid) {
3103 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003104 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003105 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003106 final Pair<Pair<Account, String>, Integer> key =
3107 new Pair<Pair<Account, String>, Integer>(
3108 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04003109 nId = accounts.credentialsPermissionNotificationIds.get(key);
3110 if (nId == null) {
3111 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3112 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
3113 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3114 nId = new NotificationId(tag, id);
3115 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003116 }
3117 }
Chris Wren717a8812017-03-31 15:34:39 -04003118 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003119 }
3120
Chris Wren717a8812017-03-31 15:34:39 -04003121 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3122 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08003123 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04003124 nId = accounts.signinRequiredNotificationIds.get(account);
3125 if (nId == null) {
3126 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3127 + ":" + account.hashCode();
3128 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3129 nId = new NotificationId(tag, id);
3130 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003131 }
3132 }
Chris Wren717a8812017-03-31 15:34:39 -04003133 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003134 }
3135
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003136 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07003137 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003138 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003139 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003140 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003141 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3142 Log.v(TAG, "addAccount: accountType " + accountType
3143 + ", response " + response
3144 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003145 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003146 + ", expectActivityLaunch " + expectActivityLaunch
3147 + ", caller's uid " + Binder.getCallingUid()
3148 + ", pid " + Binder.getCallingPid());
3149 }
Fred Quintana382601f2010-03-25 12:25:10 -07003150 if (response == null) throw new IllegalArgumentException("response is null");
3151 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003152
Amith Yamasani71e6c692013-03-24 17:39:28 -07003153 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003154 final int uid = Binder.getCallingUid();
3155 final int userId = UserHandle.getUserId(uid);
3156 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003157 try {
3158 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3159 "User is not allowed to add an account!");
3160 } catch (RemoteException re) {
3161 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003162 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003163 return;
3164 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003165 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003166 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003167 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3168 "User cannot modify accounts of this type (policy).");
3169 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003170 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003171 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3172 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003173 return;
3174 }
3175
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003176 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003177 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3178 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3179 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3180
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003181 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003182 long identityToken = clearCallingIdentity();
3183 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003184 UserAccounts accounts = getUserAccounts(usrId);
3185 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003186 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3187 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003188 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003189 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003190 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003191 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003192 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003193 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003194 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003195 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003196
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003197 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003198 protected String toDebugString(long now) {
3199 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003200 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003201 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003202 }
3203 }.bind();
3204 } finally {
3205 restoreCallingIdentity(identityToken);
3206 }
Fred Quintana60307342009-03-24 22:48:12 -07003207 }
3208
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003209 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003210 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3211 final String authTokenType, final String[] requiredFeatures,
3212 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003213 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003214 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003215 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3216 Log.v(TAG, "addAccount: accountType " + accountType
3217 + ", response " + response
3218 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003219 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003220 + ", expectActivityLaunch " + expectActivityLaunch
3221 + ", caller's uid " + Binder.getCallingUid()
3222 + ", pid " + Binder.getCallingPid()
3223 + ", for user id " + userId);
3224 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003225 Preconditions.checkArgument(response != null, "response cannot be null");
3226 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003227 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003228 if (isCrossUser(callingUid, userId)) {
3229 throw new SecurityException(
3230 String.format(
3231 "User %s trying to add account for %s" ,
3232 UserHandle.getCallingUserId(),
3233 userId));
3234 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003235
3236 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003237 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003238 try {
3239 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3240 "User is not allowed to add an account!");
3241 } catch (RemoteException re) {
3242 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003243 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003244 return;
3245 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003246 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003247 try {
3248 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3249 "User cannot modify accounts of this type (policy).");
3250 } catch (RemoteException re) {
3251 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003252 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3253 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003254 return;
3255 }
3256
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003257 final int pid = Binder.getCallingPid();
3258 final int uid = Binder.getCallingUid();
3259 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3260 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3261 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3262
3263 long identityToken = clearCallingIdentity();
3264 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003265 UserAccounts accounts = getUserAccounts(userId);
3266 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003267 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
Valentin Iftime0e7f5bb2019-10-30 19:29:33 +01003268 uid);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003269 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003270 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003271 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003272 @Override
3273 public void run() throws RemoteException {
3274 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3275 options);
3276 }
3277
3278 @Override
3279 protected String toDebugString(long now) {
3280 return super.toDebugString(now) + ", addAccount"
3281 + ", accountType " + accountType
3282 + ", requiredFeatures "
3283 + (requiredFeatures != null
3284 ? TextUtils.join(",", requiredFeatures)
3285 : null);
3286 }
3287 }.bind();
3288 } finally {
3289 restoreCallingIdentity(identityToken);
3290 }
3291 }
3292
Sandra Kwan78812282015-11-04 11:19:47 -08003293 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003294 public void startAddAccountSession(
3295 final IAccountManagerResponse response,
3296 final String accountType,
3297 final String authTokenType,
3298 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003299 final boolean expectActivityLaunch,
3300 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003301 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003302 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3303 Log.v(TAG,
3304 "startAddAccountSession: accountType " + accountType
3305 + ", response " + response
3306 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003307 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003308 + ", expectActivityLaunch " + expectActivityLaunch
3309 + ", caller's uid " + Binder.getCallingUid()
3310 + ", pid " + Binder.getCallingPid());
3311 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003312 Preconditions.checkArgument(response != null, "response cannot be null");
3313 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003314
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003315 final int uid = Binder.getCallingUid();
3316 final int userId = UserHandle.getUserId(uid);
3317 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003318 try {
3319 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3320 "User is not allowed to add an account!");
3321 } catch (RemoteException re) {
3322 }
3323 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3324 return;
3325 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003326 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003327 try {
3328 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3329 "User cannot modify accounts of this type (policy).");
3330 } catch (RemoteException re) {
3331 }
3332 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3333 userId);
3334 return;
3335 }
Sandra Kwan78812282015-11-04 11:19:47 -08003336 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003337 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3338 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3339 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3340
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003341 // Check to see if the Password should be included to the caller.
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07003342 String callerPkg = options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3343 boolean isPasswordForwardingAllowed = checkPermissionAndNote(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003344 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003345
Sandra Kwan78812282015-11-04 11:19:47 -08003346 long identityToken = clearCallingIdentity();
3347 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003348 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003349 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3350 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003351 new StartAccountSession(
3352 accounts,
3353 response,
3354 accountType,
3355 expectActivityLaunch,
3356 null /* accountName */,
3357 false /* authDetailsRequired */,
3358 true /* updateLastAuthenticationTime */,
3359 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003360 @Override
3361 public void run() throws RemoteException {
3362 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3363 requiredFeatures, options);
3364 }
3365
3366 @Override
3367 protected String toDebugString(long now) {
3368 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3369 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3370 + accountType + ", requiredFeatures "
3371 + (requiredFeatures != null ? requiredFeaturesStr : null);
3372 }
3373 }.bind();
3374 } finally {
3375 restoreCallingIdentity(identityToken);
3376 }
3377 }
3378
3379 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3380 private abstract class StartAccountSession extends Session {
3381
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003382 private final boolean mIsPasswordForwardingAllowed;
3383
3384 public StartAccountSession(
3385 UserAccounts accounts,
3386 IAccountManagerResponse response,
3387 String accountType,
3388 boolean expectActivityLaunch,
3389 String accountName,
3390 boolean authDetailsRequired,
3391 boolean updateLastAuthenticationTime,
3392 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003393 super(accounts, response, accountType, expectActivityLaunch,
3394 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3395 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003396 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003397 }
3398
3399 @Override
3400 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003401 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003402 mNumResults++;
3403 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003404 if (result != null
3405 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08003406 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003407 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08003408 intent)) {
3409 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3410 "invalid intent in bundle returned");
3411 return;
3412 }
Sandra Kwan78812282015-11-04 11:19:47 -08003413 }
Sandra Kwan78812282015-11-04 11:19:47 -08003414 IAccountManagerResponse response;
3415 if (mExpectActivityLaunch && result != null
3416 && result.containsKey(AccountManager.KEY_INTENT)) {
3417 response = mResponse;
3418 } else {
3419 response = getResponseAndClose();
3420 }
3421 if (response == null) {
3422 return;
3423 }
3424 if (result == null) {
3425 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3426 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3427 + response);
3428 }
3429 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3430 "null bundle returned");
3431 return;
3432 }
3433
3434 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3435 // All AccountManager error codes are greater
3436 // than 0
3437 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3438 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3439 return;
3440 }
3441
Hongming Jin368aa192016-07-29 14:29:54 -07003442 // Omit passwords if the caller isn't permitted to see them.
3443 if (!mIsPasswordForwardingAllowed) {
3444 result.remove(AccountManager.KEY_PASSWORD);
3445 }
3446
Sandra Kwan78812282015-11-04 11:19:47 -08003447 // Strip auth token from result.
3448 result.remove(AccountManager.KEY_AUTHTOKEN);
3449
3450 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3451 Log.v(TAG,
3452 getClass().getSimpleName() + " calling onResult() on response " + response);
3453 }
3454
3455 // Get the session bundle created by authenticator. The
3456 // bundle contains data necessary for finishing the session
3457 // later. The session bundle will be encrypted here and
3458 // decrypted later when trying to finish the session.
3459 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3460 if (sessionBundle != null) {
3461 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3462 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003463 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003464 Log.w(TAG, "Account type in session bundle doesn't match request.");
3465 }
3466 // Add accountType info to session bundle. This will
3467 // override any value set by authenticator.
3468 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3469
3470 // Encrypt session bundle before returning to caller.
3471 try {
3472 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3473 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3474 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3475 } catch (GeneralSecurityException e) {
3476 if (Log.isLoggable(TAG, Log.DEBUG)) {
3477 Log.v(TAG, "Failed to encrypt session bundle!", e);
3478 }
3479 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3480 "failed to encrypt session bundle");
3481 return;
3482 }
3483 }
3484
3485 sendResponse(response, result);
3486 }
3487 }
3488
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003489 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003490 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003491 @NonNull Bundle sessionBundle,
3492 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003493 Bundle appInfo,
3494 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003495 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003496 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003497 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3498 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003499 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003500 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003501 + ", caller's uid " + callingUid
3502 + ", caller's user id " + UserHandle.getCallingUserId()
3503 + ", pid " + Binder.getCallingPid()
3504 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003505 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003506 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003507 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3508 // Account type is added to it before encryption.
3509 if (sessionBundle == null || sessionBundle.size() == 0) {
3510 throw new IllegalArgumentException("sessionBundle is empty");
3511 }
3512
Dmitry Dementyev52745472016-12-02 10:27:45 -08003513 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003514 if (isCrossUser(callingUid, userId)) {
3515 throw new SecurityException(
3516 String.format(
3517 "User %s trying to finish session for %s without cross user permission",
3518 UserHandle.getCallingUserId(),
3519 userId));
3520 }
3521
Sandra Kwan0b84b452016-01-20 15:25:42 -08003522 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003523 sendErrorResponse(response,
3524 AccountManager.ERROR_CODE_USER_RESTRICTED,
3525 "User is not allowed to add an account!");
3526 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3527 return;
3528 }
3529
3530 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003531 final Bundle decryptedBundle;
3532 final String accountType;
3533 // First decrypt session bundle to get account type for checking permission.
3534 try {
3535 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3536 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3537 if (decryptedBundle == null) {
3538 sendErrorResponse(
3539 response,
3540 AccountManager.ERROR_CODE_BAD_REQUEST,
3541 "failed to decrypt session bundle");
3542 return;
3543 }
3544 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3545 // Account type cannot be null. This should not happen if session bundle was created
3546 // properly by #StartAccountSession.
3547 if (TextUtils.isEmpty(accountType)) {
3548 sendErrorResponse(
3549 response,
3550 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3551 "accountType is empty");
3552 return;
3553 }
3554
3555 // If by any chances, decryptedBundle contains colliding keys with
3556 // system info
3557 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3558 // update credentials flow, we should replace with the new values of the current call.
3559 if (appInfo != null) {
3560 decryptedBundle.putAll(appInfo);
3561 }
3562
3563 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003564 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003565 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3566 } catch (GeneralSecurityException e) {
3567 if (Log.isLoggable(TAG, Log.DEBUG)) {
3568 Log.v(TAG, "Failed to decrypt session bundle!", e);
3569 }
3570 sendErrorResponse(
3571 response,
3572 AccountManager.ERROR_CODE_BAD_REQUEST,
3573 "failed to decrypt session bundle");
3574 return;
3575 }
3576
Sandra Kwan0b84b452016-01-20 15:25:42 -08003577 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003578 sendErrorResponse(
3579 response,
3580 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3581 "User cannot modify accounts of this type (policy).");
3582 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3583 userId);
3584 return;
3585 }
3586
3587 long identityToken = clearCallingIdentity();
3588 try {
3589 UserAccounts accounts = getUserAccounts(userId);
3590 logRecordWithUid(
3591 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003592 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3593 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003594 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003595 new Session(
3596 accounts,
3597 response,
3598 accountType,
3599 expectActivityLaunch,
3600 true /* stripAuthTokenFromResult */,
3601 null /* accountName */,
3602 false /* authDetailsRequired */,
3603 true /* updateLastAuthenticationTime */) {
3604 @Override
3605 public void run() throws RemoteException {
3606 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3607 }
3608
3609 @Override
3610 protected String toDebugString(long now) {
3611 return super.toDebugString(now)
3612 + ", finishSession"
3613 + ", accountType " + accountType;
3614 }
3615 }.bind();
3616 } finally {
3617 restoreCallingIdentity(identityToken);
3618 }
3619 }
3620
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003621 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003622 final DevicePolicyManagerInternal dpmi =
3623 LocalServices.getService(DevicePolicyManagerInternal.class);
3624 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003625 if (dpmi == null) {
3626 intent = getDefaultCantAddAccountIntent(errorCode);
3627 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003628 intent = dpmi.createUserRestrictionSupportIntent(userId,
3629 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3630 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3631 intent = dpmi.createShowAdminSupportIntent(userId, false);
3632 }
3633 if (intent == null) {
3634 intent = getDefaultCantAddAccountIntent(errorCode);
3635 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003636 long identityToken = clearCallingIdentity();
3637 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003638 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003639 } finally {
3640 restoreCallingIdentity(identityToken);
3641 }
3642 }
3643
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003644 /**
3645 * Called when we don't know precisely who is preventing us from adding an account.
3646 */
3647 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3648 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3649 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3650 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3651 return cantAddAccount;
3652 }
3653
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003654 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003655 public void confirmCredentialsAsUser(
3656 IAccountManagerResponse response,
3657 final Account account,
3658 final Bundle options,
3659 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003660 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003661 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003662 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003663 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3664 Log.v(TAG, "confirmCredentials: " + account
3665 + ", response " + response
3666 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003667 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003668 + ", pid " + Binder.getCallingPid());
3669 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003670 // Only allow the system process to read accounts of other users
3671 if (isCrossUser(callingUid, userId)) {
3672 throw new SecurityException(
3673 String.format(
3674 "User %s trying to confirm account credentials for %s" ,
3675 UserHandle.getCallingUserId(),
3676 userId));
3677 }
Fred Quintana382601f2010-03-25 12:25:10 -07003678 if (response == null) throw new IllegalArgumentException("response is null");
3679 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003680 long identityToken = clearCallingIdentity();
3681 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003682 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003683 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003684 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003685 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003686 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003687 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003688 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003689 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003690 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003691 protected String toDebugString(long now) {
3692 return super.toDebugString(now) + ", confirmCredentials"
Hui Yu139c2482018-08-10 15:37:51 -07003693 + ", " + account.toSafeString();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003694 }
3695 }.bind();
3696 } finally {
3697 restoreCallingIdentity(identityToken);
3698 }
Fred Quintana60307342009-03-24 22:48:12 -07003699 }
3700
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003701 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003702 public void updateCredentials(IAccountManagerResponse response, final Account account,
3703 final String authTokenType, final boolean expectActivityLaunch,
3704 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003705 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003706 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3707 Log.v(TAG, "updateCredentials: " + account
3708 + ", response " + response
3709 + ", authTokenType " + authTokenType
3710 + ", expectActivityLaunch " + expectActivityLaunch
3711 + ", caller's uid " + Binder.getCallingUid()
3712 + ", pid " + Binder.getCallingPid());
3713 }
Fred Quintana382601f2010-03-25 12:25:10 -07003714 if (response == null) throw new IllegalArgumentException("response is null");
3715 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003716 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003717 long identityToken = clearCallingIdentity();
3718 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003719 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003720 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003721 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003722 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003723 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003724 public void run() throws RemoteException {
3725 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3726 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003727 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003728 protected String toDebugString(long now) {
3729 if (loginOptions != null) loginOptions.keySet();
3730 return super.toDebugString(now) + ", updateCredentials"
Hui Yu139c2482018-08-10 15:37:51 -07003731 + ", " + account.toSafeString()
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003732 + ", authTokenType " + authTokenType
3733 + ", loginOptions " + loginOptions;
3734 }
3735 }.bind();
3736 } finally {
3737 restoreCallingIdentity(identityToken);
3738 }
Fred Quintana60307342009-03-24 22:48:12 -07003739 }
3740
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003741 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003742 public void startUpdateCredentialsSession(
3743 IAccountManagerResponse response,
3744 final Account account,
3745 final String authTokenType,
3746 final boolean expectActivityLaunch,
3747 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003748 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003749 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3750 Log.v(TAG,
3751 "startUpdateCredentialsSession: " + account + ", response " + response
3752 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3753 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3754 + ", pid " + Binder.getCallingPid());
3755 }
3756 if (response == null) {
3757 throw new IllegalArgumentException("response is null");
3758 }
3759 if (account == null) {
3760 throw new IllegalArgumentException("account is null");
3761 }
Sandra Kwana578d112015-12-16 16:01:43 -08003762
3763 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003764 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003765
3766 // Check to see if the Password should be included to the caller.
3767 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07003768 boolean isPasswordForwardingAllowed = checkPermissionAndNote(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003769 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003770
Sandra Kwane68c37e2015-11-12 17:11:49 -08003771 long identityToken = clearCallingIdentity();
3772 try {
3773 UserAccounts accounts = getUserAccounts(userId);
3774 new StartAccountSession(
3775 accounts,
3776 response,
3777 account.type,
3778 expectActivityLaunch,
3779 account.name,
3780 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003781 true /* updateLastCredentialTime */,
3782 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003783 @Override
3784 public void run() throws RemoteException {
3785 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3786 loginOptions);
3787 }
3788
3789 @Override
3790 protected String toDebugString(long now) {
3791 if (loginOptions != null)
3792 loginOptions.keySet();
3793 return super.toDebugString(now)
3794 + ", startUpdateCredentialsSession"
Hui Yu139c2482018-08-10 15:37:51 -07003795 + ", " + account.toSafeString()
Sandra Kwane68c37e2015-11-12 17:11:49 -08003796 + ", authTokenType " + authTokenType
3797 + ", loginOptions " + loginOptions;
3798 }
3799 }.bind();
3800 } finally {
3801 restoreCallingIdentity(identityToken);
3802 }
3803 }
3804
3805 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003806 public void isCredentialsUpdateSuggested(
3807 IAccountManagerResponse response,
3808 final Account account,
3809 final String statusToken) {
3810 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3811 Log.v(TAG,
3812 "isCredentialsUpdateSuggested: " + account + ", response " + response
3813 + ", caller's uid " + Binder.getCallingUid()
3814 + ", pid " + Binder.getCallingPid());
3815 }
3816 if (response == null) {
3817 throw new IllegalArgumentException("response is null");
3818 }
3819 if (account == null) {
3820 throw new IllegalArgumentException("account is null");
3821 }
3822 if (TextUtils.isEmpty(statusToken)) {
3823 throw new IllegalArgumentException("status token is empty");
3824 }
3825
Sandra Kwan390c9d22016-01-12 14:13:37 -08003826 int usrId = UserHandle.getCallingUserId();
3827 long identityToken = clearCallingIdentity();
3828 try {
3829 UserAccounts accounts = getUserAccounts(usrId);
3830 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3831 false /* stripAuthTokenFromResult */, account.name,
3832 false /* authDetailsRequired */) {
3833 @Override
3834 protected String toDebugString(long now) {
3835 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
Hui Yu139c2482018-08-10 15:37:51 -07003836 + ", " + account.toSafeString();
Sandra Kwan390c9d22016-01-12 14:13:37 -08003837 }
3838
3839 @Override
3840 public void run() throws RemoteException {
3841 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3842 }
3843
3844 @Override
3845 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003846 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003847 IAccountManagerResponse response = getResponseAndClose();
3848 if (response == null) {
3849 return;
3850 }
3851
3852 if (result == null) {
3853 sendErrorResponse(
3854 response,
3855 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3856 "null bundle");
3857 return;
3858 }
3859
3860 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3861 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3862 + response);
3863 }
3864 // Check to see if an error occurred. We know if an error occurred because all
3865 // error codes are greater than 0.
3866 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3867 sendErrorResponse(response,
3868 result.getInt(AccountManager.KEY_ERROR_CODE),
3869 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3870 return;
3871 }
3872 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3873 sendErrorResponse(
3874 response,
3875 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3876 "no result in response");
3877 return;
3878 }
3879 final Bundle newResult = new Bundle();
3880 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3881 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3882 sendResponse(response, newResult);
3883 }
3884 }.bind();
3885 } finally {
3886 restoreCallingIdentity(identityToken);
3887 }
3888 }
3889
3890 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003891 public void editProperties(IAccountManagerResponse response, final String accountType,
3892 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003893 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003894 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3895 Log.v(TAG, "editProperties: accountType " + accountType
3896 + ", response " + response
3897 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003898 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003899 + ", pid " + Binder.getCallingPid());
3900 }
Fred Quintana382601f2010-03-25 12:25:10 -07003901 if (response == null) throw new IllegalArgumentException("response is null");
3902 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003903 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003904 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3905 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003906 String msg = String.format(
3907 "uid %s cannot edit authenticator properites for account type: %s",
3908 callingUid,
3909 accountType);
3910 throw new SecurityException(msg);
3911 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003912 long identityToken = clearCallingIdentity();
3913 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003914 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003915 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003916 true /* stripAuthTokenFromResult */, null /* accountName */,
3917 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003918 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003919 public void run() throws RemoteException {
3920 mAuthenticator.editProperties(this, mAccountType);
3921 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003922 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003923 protected String toDebugString(long now) {
3924 return super.toDebugString(now) + ", editProperties"
3925 + ", accountType " + accountType;
3926 }
3927 }.bind();
3928 } finally {
3929 restoreCallingIdentity(identityToken);
3930 }
Fred Quintana60307342009-03-24 22:48:12 -07003931 }
3932
Amith Yamasani12747872015-12-07 14:19:49 -08003933 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003934 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3935 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003936 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003937 throw new SecurityException("Can be called only by system UID");
3938 }
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00003939 Objects.requireNonNull(account, "account cannot be null");
3940 Objects.requireNonNull(packageName, "packageName cannot be null");
3941 Objects.requireNonNull(userHandle, "userHandle cannot be null");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003942
3943 final int userId = userHandle.getIdentifier();
3944
3945 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3946
3947 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003948 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003949 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003950 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003951 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003952 return false;
3953 }
3954 }
3955
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003956 // Returns package with oldest target SDK for given UID.
3957 private String getPackageNameForUid(int uid) {
3958 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3959 if (ArrayUtils.isEmpty(packageNames)) {
3960 return null;
3961 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003962 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003963 if (packageNames.length == 1) {
3964 return packageName;
3965 }
3966 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003967 int oldestVersion = Integer.MAX_VALUE;
3968 for (String name : packageNames) {
3969 try {
3970 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3971 if (applicationInfo != null) {
3972 int version = applicationInfo.targetSdkVersion;
3973 if (version < oldestVersion) {
3974 oldestVersion = version;
3975 packageName = name;
3976 }
3977 }
3978 } catch (NameNotFoundException e) {
3979 // skip
3980 }
3981 }
3982 return packageName;
3983 }
3984
Svet Ganovf6d424f12016-09-20 20:18:53 -07003985 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3986 int uid) {
3987 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003988 packageName = getPackageNameForUid(uid);
3989 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003990 return false;
3991 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003992 }
3993
3994 // Use null token which means any token. Having a token means the package
3995 // is trusted by the authenticator, hence it is fine to access the account.
3996 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3997 return true;
3998 }
3999 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004000 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07004001
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004002 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07004003 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004004 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07004005 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004006 }
4007
4008 @Override
4009 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
4010 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07004011 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004012 throw new SecurityException("Can be called only by system UID");
4013 }
4014
Daulet Zhanguzina3e1f212020-01-03 09:45:16 +00004015 Objects.requireNonNull(account, "account cannot be null");
4016 Objects.requireNonNull(packageName, "packageName cannot be null");
4017 Objects.requireNonNull(userHandle, "userHandle cannot be null");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004018
4019 final int userId = userHandle.getIdentifier();
4020
4021 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
4022
4023 final int uid;
4024 try {
4025 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
4026 } catch (NameNotFoundException e) {
4027 Slog.e(TAG, "Unknown package " + packageName);
4028 return null;
4029 }
4030
4031 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
4032
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07004033 final long identity = Binder.clearCallingIdentity();
4034 try {
4035 return PendingIntent.getActivityAsUser(
4036 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
4037 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
4038 null, new UserHandle(userId)).getIntentSender();
4039 } finally {
4040 Binder.restoreCallingIdentity(identity);
4041 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004042 }
4043
4044 private Intent newRequestAccountAccessIntent(Account account, String packageName,
4045 int uid, RemoteCallback callback) {
4046 return newGrantCredentialsPermissionIntent(account, packageName, uid,
4047 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
4048 @Override
4049 public void onResult(Bundle value) throws RemoteException {
4050 handleAuthenticatorResponse(true);
4051 }
4052
4053 @Override
4054 public void onRequestContinued() {
4055 /* ignore */
4056 }
4057
4058 @Override
4059 public void onError(int errorCode, String errorMessage) throws RemoteException {
4060 handleAuthenticatorResponse(false);
4061 }
4062
4063 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4064 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07004065 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004066 UserHandle.getUserHandleForUid(uid));
4067 if (callback != null) {
4068 Bundle result = new Bundle();
4069 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4070 callback.sendResult(result);
4071 }
4072 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07004073 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004074 }
4075
4076 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08004077 public boolean someUserHasAccount(@NonNull final Account account) {
4078 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4079 throw new SecurityException("Only system can check for accounts across users");
4080 }
4081 final long token = Binder.clearCallingIdentity();
4082 try {
4083 AccountAndUser[] allAccounts = getAllAccounts();
4084 for (int i = allAccounts.length - 1; i >= 0; i--) {
4085 if (allAccounts[i].account.equals(account)) {
4086 return true;
4087 }
4088 }
4089 return false;
4090 } finally {
4091 Binder.restoreCallingIdentity(token);
4092 }
4093 }
4094
Fred Quintana33269202009-04-20 16:05:10 -07004095 private class GetAccountsByTypeAndFeatureSession extends Session {
4096 private final String[] mFeatures;
4097 private volatile Account[] mAccountsOfType = null;
4098 private volatile ArrayList<Account> mAccountsWithFeatures = null;
4099 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004100 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004101 private final String mPackageName;
sunjianf29d5492017-05-11 15:42:31 -07004102 private final boolean mIncludeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004103
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004104 public GetAccountsByTypeAndFeatureSession(
4105 UserAccounts accounts,
4106 IAccountManagerResponse response,
4107 String type,
4108 String[] features,
4109 int callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004110 String packageName,
4111 boolean includeManagedNotVisible) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004112 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004113 true /* stripAuthTokenFromResult */, null /* accountName */,
4114 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004115 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07004116 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004117 mPackageName = packageName;
sunjianf29d5492017-05-11 15:42:31 -07004118 mIncludeManagedNotVisible = includeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004119 }
4120
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004121 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004122 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004123 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
sunjianf29d5492017-05-11 15:42:31 -07004124 mCallingUid, mPackageName, mIncludeManagedNotVisible);
Fred Quintana33269202009-04-20 16:05:10 -07004125 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07004126 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07004127 mCurrentAccount = 0;
4128
4129 checkAccount();
4130 }
4131
4132 public void checkAccount() {
4133 if (mCurrentAccount >= mAccountsOfType.length) {
4134 sendResult();
4135 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07004136 }
Fred Quintana33269202009-04-20 16:05:10 -07004137
Fred Quintana29e94b82010-03-10 12:11:51 -08004138 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4139 if (accountAuthenticator == null) {
4140 // It is possible that the authenticator has died, which is indicated by
4141 // mAuthenticator being set to null. If this happens then just abort.
4142 // There is no need to send back a result or error in this case since
4143 // that already happened when mAuthenticator was cleared.
4144 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4145 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4146 + " connected to the authenticator, " + toDebugString());
4147 }
4148 return;
4149 }
Fred Quintana33269202009-04-20 16:05:10 -07004150 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004151 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004152 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004153 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004154 }
4155 }
4156
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004157 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004158 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004159 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004160 mNumResults++;
4161 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004162 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004163 return;
4164 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004165 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004166 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4167 }
4168 mCurrentAccount++;
4169 checkAccount();
4170 }
4171
4172 public void sendResult() {
4173 IAccountManagerResponse response = getResponseAndClose();
4174 if (response != null) {
4175 try {
4176 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4177 for (int i = 0; i < accounts.length; i++) {
4178 accounts[i] = mAccountsWithFeatures.get(i);
4179 }
Fred Quintana56285a62010-12-02 14:20:51 -08004180 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4181 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4182 + response);
4183 }
Fred Quintana33269202009-04-20 16:05:10 -07004184 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004185 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004186 response.onResult(result);
4187 } catch (RemoteException e) {
4188 // if the caller is dead then there is no one to care about remote exceptions
4189 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4190 Log.v(TAG, "failure while notifying response", e);
4191 }
4192 }
4193 }
4194 }
4195
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004196 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004197 protected String toDebugString(long now) {
4198 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4199 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4200 }
4201 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004202
Amith Yamasani04e0d262012-02-14 11:50:53 -08004203 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004204 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004205 * @hide
4206 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004207 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004208 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004209 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004210 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004211 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4212 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004213 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004214 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004215 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004216 long identityToken = clearCallingIdentity();
4217 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004218 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004219 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004220 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004221 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004222 opPackageName,
4223 visibleAccountTypes,
4224 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004225 } finally {
4226 restoreCallingIdentity(identityToken);
4227 }
4228 }
4229
Amith Yamasanif29f2362012-04-05 18:29:52 -07004230 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004231 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004232 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004233 * @hide
4234 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004235 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004236 public AccountAndUser[] getRunningAccounts() {
4237 final int[] runningUserIds;
4238 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004239 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004240 } catch (RemoteException e) {
4241 // Running in system_server; should never happen
4242 throw new RuntimeException(e);
4243 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004244 return getAccounts(runningUserIds);
4245 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004246
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004247 /**
4248 * Returns accounts for all users, ignores visibility values.
4249 *
4250 * @hide
4251 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004252 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004253 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004254 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004255 final int[] userIds = new int[users.size()];
4256 for (int i = 0; i < userIds.length; i++) {
4257 userIds[i] = users.get(i).id;
4258 }
4259 return getAccounts(userIds);
4260 }
4261
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004262 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004263 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004264 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004265 for (int userId : userIds) {
4266 UserAccounts userAccounts = getUserAccounts(userId);
4267 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004268 Account[] accounts = getAccountsFromCache(
4269 userAccounts,
4270 null /* type */,
4271 Binder.getCallingUid(),
4272 null /* packageName */,
4273 false /* include managed not visible*/);
4274 for (Account account : accounts) {
4275 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004276 }
4277 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004278
4279 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4280 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004281 }
4282
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004283 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004284 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004285 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004286 int callingUid = Binder.getCallingUid();
4287 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004288 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004289 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004290 }
4291
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004292 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004293 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004294 String type,
4295 int userId,
4296 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004297 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004298 String opPackageName,
4299 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004300 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004301 // Only allow the system process to read accounts of other users
4302 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004303 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004304 && mContext.checkCallingOrSelfPermission(
4305 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4306 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004307 throw new SecurityException("User " + UserHandle.getCallingUserId()
4308 + " trying to get account for " + userId);
4309 }
4310
Fred Quintana56285a62010-12-02 14:20:51 -08004311 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4312 Log.v(TAG, "getAccounts: accountType " + type
4313 + ", caller's uid " + Binder.getCallingUid()
4314 + ", pid " + Binder.getCallingPid());
4315 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004316
4317 // If the original calling app was using account choosing activity
4318 // provided by the framework or authenticator we'll passing in
4319 // the original caller's uid here, which is what should be used for filtering.
4320 List<String> managedTypes =
4321 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4322 if (packageUid != -1 &&
4323 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4324 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004325 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004326 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004327 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004328 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4329 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004330 if (visibleAccountTypes.isEmpty()
4331 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004332 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004333 } else if (visibleAccountTypes.contains(type)) {
4334 // Prune the list down to just the requested type.
4335 visibleAccountTypes = new ArrayList<>();
4336 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004337 } // else aggregate all the visible accounts (it won't matter if the
4338 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004339
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004340 long identityToken = clearCallingIdentity();
4341 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004342 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004343 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004344 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004345 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004346 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004347 visibleAccountTypes,
4348 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004349 } finally {
4350 restoreCallingIdentity(identityToken);
4351 }
4352 }
4353
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004354 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004355 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004356 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004357 int callingUid,
4358 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004359 List<String> visibleAccountTypes,
4360 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004361 ArrayList<Account> visibleAccounts = new ArrayList<>();
4362 for (String visibleType : visibleAccountTypes) {
4363 Account[] accountsForType = getAccountsFromCache(
4364 userAccounts, visibleType, callingUid, callingPackage,
4365 includeUserManagedNotVisible);
4366 if (accountsForType != null) {
4367 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004368 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004369 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004370 Account[] result = new Account[visibleAccounts.size()];
4371 for (int i = 0; i < visibleAccounts.size(); i++) {
4372 result[i] = visibleAccounts.get(i);
4373 }
4374 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004375 }
4376
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004377 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004378 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4379 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004380 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004381 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004382 for (Account account : accounts) {
4383 addSharedAccountAsUser(account, userId);
4384 }
4385 }
4386
4387 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004388 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004389 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004390 accounts.accountsDb.deleteSharedAccount(account);
4391 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004392 if (accountId < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07004393 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Amith Yamasani67df64b2012-12-14 12:09:36 -08004394 + ", skipping the DB insert failed");
4395 return false;
4396 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004397 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4398 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004399 return true;
4400 }
4401
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004402 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4403 userId = handleIncomingUser(userId);
4404 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004405 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4406 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004407 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004408 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004409 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004410 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004411 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004412 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004413 }
4414 return r > 0;
4415 }
4416
Amith Yamasani67df64b2012-12-14 12:09:36 -08004417 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004418 return removeSharedAccountAsUser(account, userId, getCallingUid());
4419 }
4420
4421 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004422 userId = handleIncomingUser(userId);
4423 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004424 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4425 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004426 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004427 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004428 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004429 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004430 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004431 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004432 }
4433
Amith Yamasani67df64b2012-12-14 12:09:36 -08004434 public Account[] getSharedAccountsAsUser(int userId) {
4435 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004436 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004437 synchronized (accounts.dbLock) {
4438 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4439 Account[] accountArray = new Account[accountList.size()];
4440 accountList.toArray(accountArray);
4441 return accountArray;
4442 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004443 }
4444
4445 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004446 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004447 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004448 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004449 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004450 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004451 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4452 + callingUid + " with uid=" + uid);
4453 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004454 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004455 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004456 }
4457
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004458 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004459 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004460 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4461 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004462 int callingUid = Binder.getCallingUid();
4463 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004464 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004465 int packageUid = -1;
4466 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004467 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4468 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004469 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004470 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004471 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004472 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004473 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4474 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004475 }
sunjiand62dc392017-06-01 12:05:59 -07004476 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4477 return getAccountsAsUserForPackage(type, userId,
4478 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4479 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004480 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004481 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004482 }
4483
sunjianf29d5492017-05-11 15:42:31 -07004484 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4485 if (accounts.length < 1) return false;
4486 if (accounts.length > 1) return true;
4487 Account account = accounts[0];
4488 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4489 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4490 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4491 return false;
4492 }
4493
4494 private void startChooseAccountActivityWithAccounts(
sunjianbdabd402017-06-06 17:54:07 -07004495 IAccountManagerResponse response, Account[] accounts, String callingPackage) {
sunjianf29d5492017-05-11 15:42:31 -07004496 Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4497 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4498 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4499 new AccountManagerResponse(response));
sunjianbdabd402017-06-06 17:54:07 -07004500 intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004501
4502 mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4503 }
4504
4505 private void handleGetAccountsResult(
4506 IAccountManagerResponse response,
4507 Account[] accounts,
4508 String callingPackage) {
4509
4510 if (needToStartChooseAccountActivity(accounts, callingPackage)) {
sunjianbdabd402017-06-06 17:54:07 -07004511 startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004512 return;
4513 }
4514 if (accounts.length == 1) {
4515 Bundle bundle = new Bundle();
4516 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4517 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4518 onResult(response, bundle);
4519 return;
4520 }
4521 // No qualified account exists, return an empty Bundle.
4522 onResult(response, new Bundle());
4523 }
4524
4525 @Override
4526 public void getAccountByTypeAndFeatures(
4527 IAccountManagerResponse response,
4528 String accountType,
4529 String[] features,
4530 String opPackageName) {
4531
4532 int callingUid = Binder.getCallingUid();
4533 mAppOpsManager.checkPackage(callingUid, opPackageName);
4534 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4535 Log.v(TAG, "getAccount: accountType " + accountType
4536 + ", response " + response
4537 + ", features " + Arrays.toString(features)
4538 + ", caller's uid " + callingUid
4539 + ", pid " + Binder.getCallingPid());
4540 }
4541 if (response == null) throw new IllegalArgumentException("response is null");
4542 if (accountType == null) throw new IllegalArgumentException("accountType is null");
4543
4544 int userId = UserHandle.getCallingUserId();
4545
4546 long identityToken = clearCallingIdentity();
4547 try {
4548 UserAccounts userAccounts = getUserAccounts(userId);
4549 if (ArrayUtils.isEmpty(features)) {
4550 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4551 userAccounts, accountType, callingUid, opPackageName,
4552 true /* include managed not visible */);
4553 handleGetAccountsResult(
4554 response, accountsWithManagedNotVisible, opPackageName);
4555 return;
4556 }
4557
4558 IAccountManagerResponse retrieveAccountsResponse =
4559 new IAccountManagerResponse.Stub() {
4560 @Override
4561 public void onResult(Bundle value) throws RemoteException {
4562 Parcelable[] parcelables = value.getParcelableArray(
4563 AccountManager.KEY_ACCOUNTS);
4564 Account[] accounts = new Account[parcelables.length];
4565 for (int i = 0; i < parcelables.length; i++) {
4566 accounts[i] = (Account) parcelables[i];
4567 }
4568 handleGetAccountsResult(
4569 response, accounts, opPackageName);
4570 }
4571
4572 @Override
4573 public void onError(int errorCode, String errorMessage)
4574 throws RemoteException {
4575 // Will not be called in this case.
4576 }
4577 };
4578 new GetAccountsByTypeAndFeatureSession(
4579 userAccounts,
4580 retrieveAccountsResponse,
4581 accountType,
4582 features,
4583 callingUid,
4584 opPackageName,
4585 true /* include managed not visible */).bind();
4586 } finally {
4587 restoreCallingIdentity(identityToken);
4588 }
4589 }
4590
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004591 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004592 public void getAccountsByFeatures(
4593 IAccountManagerResponse response,
4594 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004595 String[] features,
4596 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004597 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004598 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004599 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4600 Log.v(TAG, "getAccounts: accountType " + type
4601 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004602 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004603 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004604 + ", pid " + Binder.getCallingPid());
4605 }
Fred Quintana382601f2010-03-25 12:25:10 -07004606 if (response == null) throw new IllegalArgumentException("response is null");
4607 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004608 int userId = UserHandle.getCallingUserId();
4609
Svetoslavf3f02ac2015-09-08 14:36:35 -07004610 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4611 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004612 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004613 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004614 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004615 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004616 try {
4617 response.onResult(result);
4618 } catch (RemoteException e) {
4619 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4620 }
4621 return;
4622 }
sunjianf29d5492017-05-11 15:42:31 -07004623
Fred Quintana33269202009-04-20 16:05:10 -07004624 long identityToken = clearCallingIdentity();
4625 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004626 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004627 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004628 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4629 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004630 Bundle result = new Bundle();
4631 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4632 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004633 return;
4634 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004635 new GetAccountsByTypeAndFeatureSession(
4636 userAccounts,
4637 response,
4638 type,
4639 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004640 callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004641 opPackageName,
4642 false /* include managed not visible */).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004643 } finally {
4644 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004645 }
4646 }
4647
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004648 @Override
4649 public void onAccountAccessed(String token) throws RemoteException {
4650 final int uid = Binder.getCallingUid();
4651 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4652 return;
4653 }
4654 final int userId = UserHandle.getCallingUserId();
4655 final long identity = Binder.clearCallingIdentity();
4656 try {
4657 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4658 if (Objects.equals(account.getAccessId(), token)) {
4659 // An app just accessed the account. At this point it knows about
4660 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004661 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004662 if (!hasAccountAccess(account, null, uid)) {
4663 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4664 uid, true);
4665 }
4666 }
4667 }
4668 } finally {
4669 Binder.restoreCallingIdentity(identity);
4670 }
4671 }
4672
Hongming Jin8e2bfc12018-05-30 11:01:06 -07004673 @Override
4674 public void onShellCommand(FileDescriptor in, FileDescriptor out,
4675 FileDescriptor err, String[] args, ShellCallback callback,
4676 ResultReceiver resultReceiver) {
4677 new AccountManagerServiceShellCommand(this).exec(this, in, out, err, args,
4678 callback, resultReceiver);
4679 }
4680
Fred Quintanaa698f422009-04-08 19:14:54 -07004681 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004682 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004683 IAccountManagerResponse mResponse;
4684 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004685 final boolean mExpectActivityLaunch;
4686 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004687 final String mAccountName;
4688 // Indicates if we need to add auth details(like last credential time)
4689 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004690 // If set, we need to update the last authenticated time. This is
4691 // currently
4692 // used on
4693 // successful confirming credentials.
4694 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004695
Fred Quintana33269202009-04-20 16:05:10 -07004696 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004697 private int mNumRequestContinued = 0;
4698 private int mNumErrors = 0;
4699
Fred Quintana60307342009-03-24 22:48:12 -07004700 IAccountAuthenticator mAuthenticator = null;
4701
Fred Quintana8570f742010-02-18 10:32:54 -08004702 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004703 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004704
Amith Yamasani04e0d262012-02-14 11:50:53 -08004705 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004706 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4707 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004708 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4709 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4710 }
4711
4712 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4713 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4714 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004715 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004716 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004717 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004718 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004719 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004720 mResponse = response;
4721 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004722 mExpectActivityLaunch = expectActivityLaunch;
4723 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004724 mAccountName = accountName;
4725 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004726 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004727
Fred Quintanaa698f422009-04-08 19:14:54 -07004728 synchronized (mSessions) {
4729 mSessions.put(toString(), this);
4730 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004731 if (response != null) {
4732 try {
4733 response.asBinder().linkToDeath(this, 0 /* flags */);
4734 } catch (RemoteException e) {
4735 mResponse = null;
4736 binderDied();
4737 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004738 }
Fred Quintana60307342009-03-24 22:48:12 -07004739 }
4740
Fred Quintanaa698f422009-04-08 19:14:54 -07004741 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004742 if (mResponse == null) {
4743 // this session has already been closed
4744 return null;
4745 }
Fred Quintana60307342009-03-24 22:48:12 -07004746 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004747 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004748 return response;
4749 }
4750
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004751 /**
4752 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4753 * security policy.
4754 *
4755 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004756 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004757 * supplied entries in the system Settings app.
4758 */
tiansiminga8868bf2017-09-20 13:59:13 +08004759 protected boolean checkKeyIntent(int authUid, Intent intent) {
Jeff Sharkeyd722e782017-06-12 17:33:07 -06004760 intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4761 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4762 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4763 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004764 long bid = Binder.clearCallingIdentity();
4765 try {
4766 PackageManager pm = mContext.getPackageManager();
4767 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
tiansiminga8868bf2017-09-20 13:59:13 +08004768 if (resolveInfo == null) {
4769 return false;
4770 }
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004771 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4772 int targetUid = targetActivityInfo.applicationInfo.uid;
Dan Cashman303c4bb2018-04-10 07:41:16 -07004773 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004774 if (!isExportedSystemActivity(targetActivityInfo)
Dan Cashman303c4bb2018-04-10 07:41:16 -07004775 && !pmi.hasSignatureCapability(
4776 targetUid, authUid,
4777 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004778 String pkgName = targetActivityInfo.packageName;
4779 String activityName = targetActivityInfo.name;
4780 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4781 + "does not share a signature with the supplying authenticator (%s).";
tiansiminga8868bf2017-09-20 13:59:13 +08004782 Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
4783 return false;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004784 }
tiansiminga8868bf2017-09-20 13:59:13 +08004785 return true;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004786 } finally {
4787 Binder.restoreCallingIdentity(bid);
4788 }
4789 }
4790
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004791 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4792 String className = activityInfo.name;
4793 return "android".equals(activityInfo.packageName) &&
4794 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4795 || CantAddAccountActivity.class.getName().equals(className));
4796 }
4797
Fred Quintanaa698f422009-04-08 19:14:54 -07004798 private void close() {
4799 synchronized (mSessions) {
4800 if (mSessions.remove(toString()) == null) {
4801 // the session was already closed, so bail out now
4802 return;
4803 }
4804 }
4805 if (mResponse != null) {
4806 // stop listening for response deaths
4807 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4808
4809 // clear this so that we don't accidentally send any further results
4810 mResponse = null;
4811 }
4812 cancelTimeout();
4813 unbind();
4814 }
4815
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004816 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004817 public void binderDied() {
4818 mResponse = null;
4819 close();
4820 }
4821
4822 protected String toDebugString() {
4823 return toDebugString(SystemClock.elapsedRealtime());
4824 }
4825
4826 protected String toDebugString(long now) {
4827 return "Session: expectLaunch " + mExpectActivityLaunch
4828 + ", connected " + (mAuthenticator != null)
4829 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4830 + "/" + mNumErrors + ")"
4831 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4832 }
4833
Fred Quintana60307342009-03-24 22:48:12 -07004834 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004835 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4836 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4837 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004838 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004839 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004840 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004841 }
4842 }
4843
4844 private void unbind() {
4845 if (mAuthenticator != null) {
4846 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004847 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004848 }
4849 }
4850
Fred Quintana60307342009-03-24 22:48:12 -07004851 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004852 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004853 }
4854
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004855 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004856 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004857 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004858 try {
4859 run();
4860 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004861 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004862 "remote exception");
4863 }
Fred Quintana60307342009-03-24 22:48:12 -07004864 }
4865
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004866 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004867 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004868 mAuthenticator = null;
4869 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004870 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004871 try {
4872 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4873 "disconnected");
4874 } catch (RemoteException e) {
4875 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4876 Log.v(TAG, "Session.onServiceDisconnected: "
4877 + "caught RemoteException while responding", e);
4878 }
4879 }
Fred Quintana60307342009-03-24 22:48:12 -07004880 }
4881 }
4882
Fred Quintanab839afc2009-10-14 15:57:28 -07004883 public abstract void run() throws RemoteException;
4884
Fred Quintana60307342009-03-24 22:48:12 -07004885 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004886 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004887 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004888 try {
4889 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4890 "timeout");
4891 } catch (RemoteException e) {
4892 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4893 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4894 e);
4895 }
4896 }
Fred Quintana60307342009-03-24 22:48:12 -07004897 }
4898 }
4899
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004900 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004901 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004902 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004903 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004904 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004905 if (result != null) {
4906 boolean isSuccessfulConfirmCreds = result.getBoolean(
4907 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004908 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004909 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4910 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004911 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004912 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4913 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004914 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004915 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004916 if (needUpdate || mAuthDetailsRequired) {
4917 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4918 if (needUpdate && accountPresent) {
4919 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4920 }
4921 if (mAuthDetailsRequired) {
4922 long lastAuthenticatedTime = -1;
4923 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004924 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004925 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004926 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004927 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004928 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004929 lastAuthenticatedTime);
4930 }
4931 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004932 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004933 if (result != null
4934 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08004935 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004936 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08004937 intent)) {
4938 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
4939 "invalid intent in bundle returned");
4940 return;
4941 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004942 }
4943 if (result != null
4944 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004945 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4946 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004947 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4948 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004949 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4950 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004951 }
Fred Quintana60307342009-03-24 22:48:12 -07004952 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004953 IAccountManagerResponse response;
4954 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004955 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004956 response = mResponse;
4957 } else {
4958 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004959 }
Fred Quintana60307342009-03-24 22:48:12 -07004960 if (response != null) {
4961 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004962 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004963 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4964 Log.v(TAG, getClass().getSimpleName()
4965 + " calling onError() on response " + response);
4966 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004967 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004968 "null bundle returned");
4969 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004970 if (mStripAuthTokenFromResult) {
4971 result.remove(AccountManager.KEY_AUTHTOKEN);
4972 }
Fred Quintana56285a62010-12-02 14:20:51 -08004973 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4974 Log.v(TAG, getClass().getSimpleName()
4975 + " calling onResult() on response " + response);
4976 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004977 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4978 (intent == null)) {
4979 // All AccountManager error codes are greater than 0
4980 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4981 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4982 } else {
4983 response.onResult(result);
4984 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004985 }
Fred Quintana60307342009-03-24 22:48:12 -07004986 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004987 // if the caller is dead then there is no one to care about remote exceptions
4988 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4989 Log.v(TAG, "failure while notifying response", e);
4990 }
Fred Quintana60307342009-03-24 22:48:12 -07004991 }
4992 }
4993 }
Fred Quintana60307342009-03-24 22:48:12 -07004994
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004995 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004996 public void onRequestContinued() {
4997 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004998 }
4999
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005000 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005001 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07005002 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07005003 IAccountManagerResponse response = getResponseAndClose();
5004 if (response != null) {
5005 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08005006 Log.v(TAG, getClass().getSimpleName()
5007 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07005008 }
5009 try {
5010 response.onError(errorCode, errorMessage);
5011 } catch (RemoteException e) {
5012 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5013 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
5014 }
5015 }
5016 } else {
5017 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5018 Log.v(TAG, "Session.onError: already closed");
5019 }
Fred Quintana60307342009-03-24 22:48:12 -07005020 }
5021 }
Fred Quintanab839afc2009-10-14 15:57:28 -07005022
5023 /**
5024 * find the component name for the authenticator and initiate a bind
5025 * if no authenticator or the bind fails then return false, otherwise return true
5026 */
5027 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005028 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
5029 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
5030 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07005031 if (authenticatorInfo == null) {
5032 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5033 Log.v(TAG, "there is no authenticator for " + authenticatorType
5034 + ", bailing out");
5035 }
5036 return false;
5037 }
5038
Jeff Sharkeyce18c812016-04-27 16:00:41 -06005039 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06005040 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07005041 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
5042 + " which isn't encryption aware");
5043 return false;
5044 }
5045
Fred Quintanab839afc2009-10-14 15:57:28 -07005046 Intent intent = new Intent();
5047 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
5048 intent.setComponent(authenticatorInfo.componentName);
5049 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5050 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
5051 }
Hongming Jin8e2bfc12018-05-30 11:01:06 -07005052 int flags = Context.BIND_AUTO_CREATE;
5053 if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
5054 flags |= Context.BIND_ALLOW_INSTANT;
5055 }
5056 if (!mContext.bindServiceAsUser(intent, this, flags, UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07005057 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5058 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
5059 }
5060 return false;
5061 }
5062
Fred Quintanab839afc2009-10-14 15:57:28 -07005063 return true;
5064 }
Fred Quintana60307342009-03-24 22:48:12 -07005065 }
5066
Svet Ganov5d09c992016-09-07 09:57:41 -07005067 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07005068 MessageHandler(Looper looper) {
5069 super(looper);
5070 }
Costin Manolache3348f142009-09-29 18:58:36 -07005071
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07005072 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005073 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07005074 switch (msg.what) {
5075 case MESSAGE_TIMED_OUT:
5076 Session session = (Session)msg.obj;
5077 session.onTimedOut();
5078 break;
5079
Amith Yamasani5be347b2013-03-31 17:44:31 -07005080 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00005081 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07005082 break;
5083
Fred Quintana60307342009-03-24 22:48:12 -07005084 default:
5085 throw new IllegalStateException("unhandled message: " + msg.what);
5086 }
5087 }
5088 }
5089
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005090 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005091 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005092 }
5093
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005094 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005095 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005096 }
5097
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005098 /*
5099 * This function receives an opened writable database.
5100 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005101 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005102 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005103 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005104 }
5105
5106 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005107 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005108 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005109 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005110 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005111
5112 class LogRecordTask implements Runnable {
5113 private final String action;
5114 private final String tableName;
5115 private final long accountId;
5116 private final UserAccounts userAccount;
5117 private final int callingUid;
5118 private final long userDebugDbInsertionPoint;
5119
5120 LogRecordTask(final String action,
5121 final String tableName,
5122 final long accountId,
5123 final UserAccounts userAccount,
5124 final int callingUid,
5125 final long userDebugDbInsertionPoint) {
5126 this.action = action;
5127 this.tableName = tableName;
5128 this.accountId = accountId;
5129 this.userAccount = userAccount;
5130 this.callingUid = callingUid;
5131 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5132 }
5133
Andrew Scullc7770d62017-05-22 17:49:58 +01005134 @Override
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005135 public void run() {
Dmitry Dementyev47443192018-10-24 13:31:59 -07005136 synchronized (userAccount.accountsDb.mDebugStatementLock) {
5137 SQLiteStatement logStatement = userAccount.accountsDb.getStatementForLogging();
5138 if (logStatement == null) {
5139 return; // Can't log.
5140 }
5141 logStatement.bindLong(1, accountId);
5142 logStatement.bindString(2, action);
5143 logStatement.bindString(3, mDateFormat.format(new Date()));
5144 logStatement.bindLong(4, callingUid);
5145 logStatement.bindString(5, tableName);
5146 logStatement.bindLong(6, userDebugDbInsertionPoint);
5147 try {
5148 logStatement.execute();
5149 } catch (IllegalStateException e) {
5150 // Guard against crash, DB can already be closed
5151 // since this statement is executed on a handler thread
5152 Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
5153 + " action=" + action + " tableName=" + tableName + " Error: " + e);
5154 } finally {
5155 logStatement.clearBindings();
5156 }
Tetsutoki Shiozawabe2d96a2017-10-24 18:44:00 +09005157 }
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005158 }
5159 }
Dmitry Dementyev47443192018-10-24 13:31:59 -07005160 long insertionPoint = userAccount.accountsDb.reserveDebugDbInsertionPoint();
5161 if (insertionPoint != -1) {
5162 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5163 callingUid, insertionPoint);
5164 mHandler.post(logTask);
5165 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005166 }
5167
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005168 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07005169 return asBinder();
5170 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005171
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005172 /**
5173 * Searches array of arguments for the specified string
5174 * @param args array of argument strings
5175 * @param value value to search for
5176 * @return true if the value is contained in the array
5177 */
5178 private static boolean scanArgs(String[] args, String value) {
5179 if (args != null) {
5180 for (String arg : args) {
5181 if (value.equals(arg)) {
5182 return true;
5183 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005184 }
5185 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005186 return false;
5187 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005188
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005189 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005190 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005191 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005192 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005193 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07005194
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005195 final List<UserInfo> users = getUserManager().getUsers();
5196 for (UserInfo user : users) {
5197 ipw.println("User " + user + ":");
5198 ipw.increaseIndent();
5199 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5200 ipw.println();
5201 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08005202 }
5203 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005204
Amith Yamasani04e0d262012-02-14 11:50:53 -08005205 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5206 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005207 if (isCheckinRequest) {
5208 // This is a checkin request. *Only* upload the account types and the count of
5209 // each.
5210 synchronized (userAccounts.dbLock) {
5211 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5212 }
5213 } else {
5214 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5215 Process.SYSTEM_UID, null /* packageName */, false);
5216 fout.println("Accounts: " + accounts.length);
5217 for (Account account : accounts) {
Makoto Onukib9425222019-01-23 11:35:43 -08005218 fout.println(" " + account.toString());
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005219 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005220
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005221 // Add debug information.
5222 fout.println();
5223 synchronized (userAccounts.dbLock) {
5224 userAccounts.accountsDb.dumpDebugTable(fout);
5225 }
5226 fout.println();
5227 synchronized (mSessions) {
5228 final long now = SystemClock.elapsedRealtime();
5229 fout.println("Active Sessions: " + mSessions.size());
5230 for (Session session : mSessions.values()) {
5231 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005232 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005233 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005234
5235 fout.println();
5236 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Tony Mak6d14d772017-07-13 17:49:46 +08005237
5238 boolean isUserUnlocked;
5239 synchronized (mUsers) {
5240 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
5241 }
5242 // Following logs are printed only when user is unlocked.
5243 if (!isUserUnlocked) {
5244 return;
5245 }
5246 fout.println();
5247 synchronized (userAccounts.dbLock) {
5248 Map<Account, Map<String, Integer>> allVisibilityValues =
5249 userAccounts.accountsDb.findAllVisibilityValues();
5250 fout.println("Account visibility:");
5251 for (Account account : allVisibilityValues.keySet()) {
5252 fout.println(" " + account.name);
5253 Map<String, Integer> visibilities = allVisibilityValues.get(account);
5254 for (Entry<String, Integer> entry : visibilities.entrySet()) {
5255 fout.println(" " + entry.getKey() + ", " + entry.getValue());
5256 }
5257 }
5258 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005259 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005260 }
5261
Amith Yamasani04e0d262012-02-14 11:50:53 -08005262 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005263 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005264 long identityToken = clearCallingIdentity();
5265 try {
5266 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5267 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5268 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005269
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005270 if (intent.getComponent() != null &&
5271 GrantCredentialsPermissionActivity.class.getName().equals(
5272 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005273 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005274 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005275 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04005276 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5277 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005278
Fred Quintana33f889a2009-09-14 17:31:26 -07005279 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005280 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05005281 Notification n =
5282 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005283 .setWhen(0)
5284 .setSmallIcon(android.R.drawable.stat_sys_warning)
5285 .setColor(contextForUser.getColor(
5286 com.android.internal.R.color.system_notification_accent_color))
5287 .setContentTitle(String.format(notificationTitleFormat, account.name))
5288 .setContentText(message)
5289 .setContentIntent(PendingIntent.getActivityAsUser(
5290 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005291 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005292 .build();
Chris Wren717a8812017-03-31 15:34:39 -04005293 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005294 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005295 } finally {
5296 restoreCallingIdentity(identityToken);
5297 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005298 }
5299
Chris Wren717a8812017-03-31 15:34:39 -04005300 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005301 String packageName, int userId) {
5302 final long token = clearCallingIdentity();
5303 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005304 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005305 try {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005306 // The calling uid must match either the package or op package, so use an op
5307 // package that matches the cleared calling identity.
5308 notificationManager.enqueueNotificationWithTag(packageName, "android",
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04005309 id.mTag, id.mId, notification, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005310 } catch (RemoteException e) {
5311 /* ignore - local call */
5312 }
5313 } finally {
5314 Binder.restoreCallingIdentity(token);
5315 }
Fred Quintana56285a62010-12-02 14:20:51 -08005316 }
5317
Chris Wren717a8812017-03-31 15:34:39 -04005318 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005319 cancelNotification(id, mContext.getPackageName(), user);
5320 }
5321
Chris Wren717a8812017-03-31 15:34:39 -04005322 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005323 long identityToken = clearCallingIdentity();
5324 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005325 INotificationManager service = mInjector.getNotificationManager();
Julia Reynoldse4a47dd2019-06-07 13:40:59 -04005326 service.cancelNotificationWithTag(
5327 packageName, "android", id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005328 } catch (RemoteException e) {
5329 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005330 } finally {
5331 restoreCallingIdentity(identityToken);
5332 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005333 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005334
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005335 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005336 final long identity = Binder.clearCallingIdentity();
5337 try {
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005338 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005339 IPackageManager pm = ActivityThread.getPackageManager();
5340 for (String perm : permissions) {
5341 if (pm.checkPermission(perm, packageName, userId)
5342 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005343 // Checks runtime permission revocation.
5344 final int opCode = AppOpsManager.permissionToOpCode(perm);
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005345 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.checkOpNoThrow(
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005346 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5347 return true;
5348 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005349 }
5350 }
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005351 } catch (NameNotFoundException | RemoteException e) {
5352 // Assume permission is not granted if an error accrued.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005353 } finally {
5354 Binder.restoreCallingIdentity(identity);
5355 }
5356 return false;
5357 }
5358
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005359 /**
5360 * Checks that package has at least one of given permissions and makes note of app
5361 * performing the action.
5362 */
5363 private boolean checkPermissionAndNote(String opPackageName, int callingUid,
5364 String... permissions) {
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005365 for (String perm : permissions) {
5366 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5367 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5368 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5369 }
5370 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005371 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005372 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5373 return true;
5374 }
5375 }
5376 }
5377 return false;
5378 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005379
Amith Yamasani67df64b2012-12-14 12:09:36 -08005380 private int handleIncomingUser(int userId) {
5381 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005382 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005383 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5384 } catch (RemoteException re) {
5385 // Shouldn't happen, local.
5386 }
5387 return userId;
5388 }
5389
Christopher Tateccbf84f2013-05-08 15:25:41 -07005390 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005391 String[] packages;
5392 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005393 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005394 packages = mPackageManager.getPackagesForUid(callingUid);
sunjian9ae597b62017-08-14 15:45:04 -07005395 if (packages == null) {
5396 Log.d(TAG, "No packages for callingUid " + callingUid);
Fred Quintana7be59642009-08-24 18:29:25 -07005397 return false;
5398 }
sunjian9ae597b62017-08-14 15:45:04 -07005399 for (String name : packages) {
5400 try {
5401 PackageInfo packageInfo =
5402 mPackageManager.getPackageInfo(name, 0 /* flags */);
5403 if (packageInfo != null
5404 && (packageInfo.applicationInfo.privateFlags
5405 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
5406 return true;
5407 }
5408 } catch (PackageManager.NameNotFoundException e) {
5409 Log.d(TAG, "Package not found " + e.getMessage());
5410 }
5411 }
5412 } finally {
5413 Binder.restoreCallingIdentity(identityToken);
Fred Quintana7be59642009-08-24 18:29:25 -07005414 }
5415 return false;
5416 }
5417
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005418 private boolean permissionIsGranted(
5419 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005420 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5421 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5422 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5423 }
5424 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005425 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005426
5427 if (isPrivileged(callerUid)) {
5428 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5429 Log.v(TAG, "Access to " + account + " granted calling uid "
5430 + callerUid + " privileged");
5431 }
5432 return true;
5433 }
5434 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5435 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5436 Log.v(TAG, "Access to " + account + " granted calling uid "
5437 + callerUid + " manages the account");
5438 }
5439 return true;
5440 }
5441 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5442 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5443 Log.v(TAG, "Access to " + account + " granted calling uid "
5444 + callerUid + " user granted access");
5445 }
5446 return true;
5447 }
5448
5449 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5450 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5451 }
5452
5453 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005454 }
5455
Svetoslavf3f02ac2015-09-08 14:36:35 -07005456 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5457 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005458 if (accountType == null) {
5459 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005460 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005461 return getTypesVisibleToCaller(callingUid, userId,
5462 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005463 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005464 }
5465
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005466 // Method checks visibility for applications targeing API level below {@link
5467 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005468 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005469 private boolean checkGetAccountsPermission(String packageName, int userId) {
5470 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005471 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5472 }
5473
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005474 private boolean checkReadContactsPermission(String packageName, int userId) {
5475 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005476 }
5477
5478 // Heuristic to check that account type may be associated with some contacts data and
5479 // therefore READ_CONTACTS permission grants the access to account by default.
5480 private boolean accountTypeManagesContacts(String accountType, int userId) {
5481 if (accountType == null) {
5482 return false;
5483 }
5484 long identityToken = Binder.clearCallingIdentity();
5485 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5486 try {
5487 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5488 } finally {
5489 Binder.restoreCallingIdentity(identityToken);
5490 }
5491 // Check contacts related permissions for authenticator.
5492 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5493 : serviceInfos) {
5494 if (accountType.equals(serviceInfo.type.type)) {
Dmitry Dementyev6fb038c2019-04-15 11:44:00 -07005495 return isPermittedForPackage(serviceInfo.type.packageName, userId,
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005496 Manifest.permission.WRITE_CONTACTS);
5497 }
5498 }
5499 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005500 }
5501
5502 /**
5503 * Method checks package uid and signature with Authenticator which manages accountType.
5504 *
5505 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5506 * SIGNATURE_CHECK_MISMATCH otherwise.
5507 */
5508 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5509 if (accountType == null) {
5510 return SIGNATURE_CHECK_MISMATCH;
5511 }
5512
5513 long identityToken = Binder.clearCallingIdentity();
5514 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5515 try {
5516 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5517 } finally {
5518 Binder.restoreCallingIdentity(identityToken);
5519 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005520 // Check for signature match with Authenticator.LocalServices.getService(PackageManagerInternal.class);
5521 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005522 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5523 : serviceInfos) {
5524 if (accountType.equals(serviceInfo.type.type)) {
5525 if (serviceInfo.uid == callingUid) {
5526 return SIGNATURE_CHECK_UID_MATCH;
5527 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005528 if (pmi.hasSignatureCapability(
5529 serviceInfo.uid, callingUid,
5530 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005531 return SIGNATURE_CHECK_MATCH;
5532 }
5533 }
5534 }
5535 return SIGNATURE_CHECK_MISMATCH;
5536 }
5537
5538 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005539 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5540 if (accountType == null) {
5541 return false;
5542 } else {
5543 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5544 }
5545 }
5546
Svetoslavf3f02ac2015-09-08 14:36:35 -07005547 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5548 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005549 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005550 }
5551
5552 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005553 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005554 }
5555
5556 private List<String> getTypesForCaller(
5557 int callingUid, int userId, boolean isOtherwisePermitted) {
5558 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005559 long identityToken = Binder.clearCallingIdentity();
5560 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5561 try {
5562 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5563 } finally {
5564 Binder.restoreCallingIdentity(identityToken);
5565 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005566
5567 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005568 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005569 serviceInfos) {
Dan Cashman303c4bb2018-04-10 07:41:16 -07005570 if (isOtherwisePermitted || pmi.hasSignatureCapability(
5571 serviceInfo.uid, callingUid,
5572 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005573 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005574 }
5575 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005576 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005577 }
5578
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005579 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5580 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5581 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5582 if (account.name.equals(accountName)) {
5583 return true;
5584 }
5585 }
5586 }
5587 return false;
5588 }
5589
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005590 private static void checkManageUsersPermission(String message) {
5591 if (ActivityManager.checkComponentPermission(
5592 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5593 != PackageManager.PERMISSION_GRANTED) {
5594 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5595 }
5596 }
5597
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005598 private static void checkManageOrCreateUsersPermission(String message) {
5599 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5600 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5601 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5602 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5603 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5604 + message);
5605 }
5606 }
5607
Amith Yamasani04e0d262012-02-14 11:50:53 -08005608 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5609 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005610 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005611 return true;
5612 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005613 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005614 synchronized (accounts.dbLock) {
5615 synchronized (accounts.cacheLock) {
5616 long grantsCount;
5617 if (authTokenType != null) {
5618 grantsCount = accounts.accountsDb
5619 .findMatchingGrantsCount(callerUid, authTokenType, account);
5620 } else {
5621 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5622 account);
5623 }
5624 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005625
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005626 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5627 // TODO: Skip this check when running automated tests. Replace this
5628 // with a more general solution.
Hui Yu139c2482018-08-10 15:37:51 -07005629 Log.d(TAG, "no credentials permission for usage of "
5630 + account.toSafeString() + ", "
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005631 + authTokenType + " by uid " + callerUid
5632 + " but ignoring since device is in test harness.");
5633 return true;
5634 }
5635 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005636 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005637 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005638 }
5639
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005640 private boolean isSystemUid(int callingUid) {
5641 String[] packages = null;
5642 long ident = Binder.clearCallingIdentity();
5643 try {
5644 packages = mPackageManager.getPackagesForUid(callingUid);
Alex Chau81a47cd2018-01-02 16:49:14 +00005645 if (packages != null) {
5646 for (String name : packages) {
5647 try {
5648 PackageInfo packageInfo =
5649 mPackageManager.getPackageInfo(name, 0 /* flags */);
5650 if (packageInfo != null
5651 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5652 != 0) {
5653 return true;
5654 }
5655 } catch (NameNotFoundException e) {
5656 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5657 }
5658 }
5659 } else {
5660 Log.w(TAG, "No known packages with uid " + callingUid);
5661 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005662 } finally {
5663 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005664 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005665 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005666 }
5667
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005668 /** Succeeds if any of the specified permissions are granted. */
5669 private void checkReadAccountsPermitted(
5670 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005671 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005672 int userId,
5673 String opPackageName) {
5674 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005675 String msg = String.format(
5676 "caller uid %s cannot access %s accounts",
5677 callingUid,
5678 accountType);
5679 Log.w(TAG, " " + msg);
5680 throw new SecurityException(msg);
5681 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005682 }
5683
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005684 private boolean canUserModifyAccounts(int userId, int callingUid) {
5685 // the managing app can always modify accounts
5686 if (isProfileOwner(callingUid)) {
5687 return true;
5688 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005689 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5690 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5691 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005692 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005693 return true;
5694 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005695
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005696 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5697 // the managing app can always modify accounts
5698 if (isProfileOwner(callingUid)) {
5699 return true;
5700 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005701 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5702 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005703 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005704 if (typesArray == null) {
5705 return true;
5706 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005707 for (String forbiddenType : typesArray) {
5708 if (forbiddenType.equals(accountType)) {
5709 return false;
5710 }
5711 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005712 return true;
5713 }
5714
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005715 private boolean isProfileOwner(int uid) {
5716 final DevicePolicyManagerInternal dpmi =
5717 LocalServices.getService(DevicePolicyManagerInternal.class);
5718 return (dpmi != null)
5719 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5720 }
5721
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005722 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005723 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5724 throws RemoteException {
5725 final int callingUid = getCallingUid();
5726
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005727 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005728 throw new SecurityException();
5729 }
5730
5731 if (value) {
5732 grantAppPermission(account, authTokenType, uid);
5733 } else {
5734 revokeAppPermission(account, authTokenType, uid);
5735 }
5736 }
5737
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005738 /**
5739 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5740 * <p>
5741 * Although this is public it can only be accessed via the AccountManagerService object
5742 * which is in the system. This means we don't need to protect it with permissions.
5743 * @hide
5744 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005745 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005746 if (account == null || authTokenType == null) {
5747 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005748 return;
5749 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005750 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005751 synchronized (accounts.dbLock) {
5752 synchronized (accounts.cacheLock) {
5753 long accountId = accounts.accountsDb.findDeAccountId(account);
5754 if (accountId >= 0) {
5755 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5756 }
5757 cancelNotification(
5758 getCredentialPermissionNotificationId(account, authTokenType, uid),
5759 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005760
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005761 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5762 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005763 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005764
5765 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5766 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5767 : mAppPermissionChangeListeners) {
5768 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5769 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005770 }
5771
5772 /**
5773 * Don't allow callers with the given uid permission to get credentials for
5774 * account/authTokenType.
5775 * <p>
5776 * Although this is public it can only be accessed via the AccountManagerService object
5777 * which is in the system. This means we don't need to protect it with permissions.
5778 * @hide
5779 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005780 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005781 if (account == null || authTokenType == null) {
5782 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005783 return;
5784 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005785 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005786 synchronized (accounts.dbLock) {
5787 synchronized (accounts.cacheLock) {
5788 accounts.accountsDb.beginTransaction();
5789 try {
5790 long accountId = accounts.accountsDb.findDeAccountId(account);
5791 if (accountId >= 0) {
5792 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5793 accountId, authTokenType, uid);
5794 accounts.accountsDb.setTransactionSuccessful();
5795 }
5796 } finally {
5797 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005798 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005799
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005800 cancelNotification(
5801 getCredentialPermissionNotificationId(account, authTokenType, uid),
5802 UserHandle.of(accounts.userId));
5803 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005804 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005805
5806 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5807 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5808 : mAppPermissionChangeListeners) {
5809 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5810 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005811 }
Fred Quintana56285a62010-12-02 14:20:51 -08005812
Amith Yamasani04e0d262012-02-14 11:50:53 -08005813 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5814 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005815 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005816 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005817 for (Account curAccount : oldAccountsForType) {
5818 if (!curAccount.equals(account)) {
5819 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005820 }
5821 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005822 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005823 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005824 } else {
5825 Account[] newAccountsForType = new Account[newAccountsList.size()];
5826 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005827 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005828 }
Fred Quintana56285a62010-12-02 14:20:51 -08005829 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005830 accounts.userDataCache.remove(account);
5831 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005832 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005833 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005834 }
5835
5836 /**
5837 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005838 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5839 * processes and if you will return this account to apps you should return the result.
5840 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005841 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005842 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005843 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005844 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5845 Account[] newAccountsForType = new Account[oldLength + 1];
5846 if (accountsForType != null) {
5847 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005848 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005849 String token = account.getAccessId() != null ? account.getAccessId()
5850 : UUID.randomUUID().toString();
5851 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005852 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005853 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005854 }
5855
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005856 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005857 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005858 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005859 String visibilityFilterPackage = callingPackage;
5860 if (visibilityFilterPackage == null) {
5861 visibilityFilterPackage = getPackageNameForUid(callingUid);
5862 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005863 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005864 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005865 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005866 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5867 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5868 || (includeManagedNotVisible
5869 && (visibility
5870 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5871 firstPass.put(account, visibility);
5872 }
5873 }
5874 Map<Account, Integer> secondPass =
5875 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5876
5877 Account[] filtered = new Account[secondPass.size()];
5878 filtered = secondPass.keySet().toArray(filtered);
5879 return filtered;
5880 }
5881
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005882 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005883 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005884 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005885 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005886 // first part is to filter shared accounts.
5887 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005888 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005889 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005890 return unfiltered;
5891 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005892 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005893 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005894 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005895 if (packages == null) {
5896 packages = new String[] {};
5897 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005898 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005899 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005900 // This might be a temporary way to specify a visible list
5901 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005902 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5903 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005904 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005905 return unfiltered;
5906 }
5907 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005908 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005909 if (ArrayUtils.isEmpty(sharedAccounts)) {
5910 return unfiltered;
5911 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005912 String requiredAccountType = "";
5913 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005914 // If there's an explicit callingPackage specified, check if that package
5915 // opted in to see restricted accounts.
5916 if (callingPackage != null) {
5917 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005918 if (pi != null && pi.restrictedAccountType != null) {
5919 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005920 }
5921 } else {
5922 // Otherwise check if the callingUid has a package that has opted in
5923 for (String packageName : packages) {
5924 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5925 if (pi != null && pi.restrictedAccountType != null) {
5926 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005927 break;
5928 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005929 }
5930 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005931 } catch (NameNotFoundException e) {
5932 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005933 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005934 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005935 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5936 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005937 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005938 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005939 } else {
5940 boolean found = false;
5941 for (Account shared : sharedAccounts) {
5942 if (shared.equals(account)) {
5943 found = true;
5944 break;
5945 }
5946 }
5947 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005948 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005949 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005950 }
5951 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005952 return filtered;
5953 } else {
5954 return unfiltered;
5955 }
5956 }
5957
Amith Yamasani27db4682013-03-30 17:07:47 -07005958 /*
5959 * packageName can be null. If not null, it should be used to filter out restricted accounts
5960 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005961 *
5962 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5963 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005964 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005965 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005966 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005967 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005968 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5969 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005970 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005971 Account[] accounts;
5972 synchronized (userAccounts.cacheLock) {
5973 accounts = userAccounts.accountCache.get(accountType);
5974 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005975 if (accounts == null) {
5976 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005977 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005978 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5979 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005980 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005981 } else {
5982 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005983 Account[] accountsArray;
5984 synchronized (userAccounts.cacheLock) {
5985 for (Account[] accounts : userAccounts.accountCache.values()) {
5986 totalLength += accounts.length;
5987 }
5988 if (totalLength == 0) {
5989 return EMPTY_ACCOUNT_ARRAY;
5990 }
5991 accountsArray = new Account[totalLength];
5992 totalLength = 0;
5993 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5994 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5995 accountsOfType.length);
5996 totalLength += accountsOfType.length;
5997 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005998 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005999 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006000 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08006001 }
6002 }
6003
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006004 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006005 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08006006 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006007 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006008 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006009 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08006010 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006011 }
6012 if (value == null) {
6013 userDataForAccount.remove(key);
6014 } else {
6015 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08006016 }
6017 }
6018
Carlos Valdivia91979be2015-05-22 14:11:35 -07006019 protected String readCachedTokenInternal(
6020 UserAccounts accounts,
6021 Account account,
6022 String tokenType,
6023 String callingPackage,
6024 byte[] pkgSigDigest) {
Dmitry Dementyev18f0ca92017-06-12 17:56:47 -07006025 synchronized (accounts.cacheLock) {
6026 return accounts.accountTokenCaches.get(
6027 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07006028 }
6029 }
6030
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006031 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006032 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08006033 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006034 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006035 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006036 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08006037 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006038 }
6039 if (value == null) {
6040 authTokensForAccount.remove(key);
6041 } else {
6042 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08006043 }
6044 }
6045
Amith Yamasani04e0d262012-02-14 11:50:53 -08006046 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
6047 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006048 // Fast path - check if account is already cached
6049 synchronized (accounts.cacheLock) {
6050 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6051 if (authTokensForAccount != null) {
6052 return authTokensForAccount.get(authTokenType);
6053 }
6054 }
6055 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07006056 synchronized (accounts.dbLock) {
6057 synchronized (accounts.cacheLock) {
6058 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6059 if (authTokensForAccount == null) {
6060 // need to populate the cache for this account
6061 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6062 accounts.authTokenCache.put(account, authTokensForAccount);
6063 }
6064 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08006065 }
Fred Quintana56285a62010-12-02 14:20:51 -08006066 }
6067 }
6068
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006069 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
6070 Map<String, String> userDataForAccount;
6071 // Fast path - check if data is already cached
6072 synchronized (accounts.cacheLock) {
6073 userDataForAccount = accounts.userDataCache.get(account);
6074 }
6075 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00006076 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006077 synchronized (accounts.dbLock) {
6078 synchronized (accounts.cacheLock) {
6079 userDataForAccount = accounts.userDataCache.get(account);
6080 if (userDataForAccount == null) {
6081 // need to populate the cache for this account
6082 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6083 accounts.userDataCache.put(account, userDataForAccount);
6084 }
6085 }
6086 }
Fred Quintana56285a62010-12-02 14:20:51 -08006087 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00006088 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08006089 }
6090
Kenny Guy07ad8dc2014-09-01 20:56:12 +01006091 private Context getContextForUser(UserHandle user) {
6092 try {
6093 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
6094 } catch (NameNotFoundException e) {
6095 // Default to mContext, not finding the package system is running as is unlikely.
6096 return mContext;
6097 }
6098 }
Sandra Kwan78812282015-11-04 11:19:47 -08006099
6100 private void sendResponse(IAccountManagerResponse response, Bundle result) {
6101 try {
6102 response.onResult(result);
6103 } catch (RemoteException e) {
6104 // if the caller is dead then there is no one to care about remote
6105 // exceptions
6106 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6107 Log.v(TAG, "failure while notifying response", e);
6108 }
6109 }
6110 }
6111
6112 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6113 String errorMessage) {
6114 try {
6115 response.onError(errorCode, errorMessage);
6116 } catch (RemoteException e) {
6117 // if the caller is dead then there is no one to care about remote
6118 // exceptions
6119 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6120 Log.v(TAG, "failure while notifying response", e);
6121 }
6122 }
6123 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006124
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006125 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07006126 private final Object mLock = new Object();
6127
6128 @GuardedBy("mLock")
6129 private AccountManagerBackupHelper mBackupHelper;
6130
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006131 @Override
6132 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6133 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6134 if (account == null) {
6135 Slog.w(TAG, "account cannot be null");
6136 return;
6137 }
6138 if (packageName == null) {
6139 Slog.w(TAG, "packageName cannot be null");
6140 return;
6141 }
6142 if (userId < UserHandle.USER_SYSTEM) {
6143 Slog.w(TAG, "user id must be concrete");
6144 return;
6145 }
6146 if (callback == null) {
6147 Slog.w(TAG, "callback cannot be null");
6148 return;
6149 }
6150
Dmitry Dementyev7b3ea132017-05-10 12:45:02 -07006151 int visibility =
6152 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6153 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6154 Slog.w(TAG, "requestAccountAccess: account is hidden");
6155 return;
6156 }
6157
Svet Ganovf6d424f12016-09-20 20:18:53 -07006158 if (AccountManagerService.this.hasAccountAccess(account, packageName,
6159 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006160 Bundle result = new Bundle();
6161 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6162 callback.sendResult(result);
6163 return;
6164 }
6165
6166 final int uid;
6167 try {
Dmitry Dementyev940b7602018-10-09 16:40:06 -07006168 long identityToken = clearCallingIdentity();
6169 try {
6170 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6171 } finally {
6172 restoreCallingIdentity(identityToken);
6173 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006174 } catch (NameNotFoundException e) {
6175 Slog.e(TAG, "Unknown package " + packageName);
6176 return;
6177 }
6178
6179 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006180 final UserAccounts userAccounts;
6181 synchronized (mUsers) {
6182 userAccounts = mUsers.get(userId);
6183 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04006184 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006185 doNotification(userAccounts, account, null, intent, packageName, userId);
6186 }
6187
6188 @Override
6189 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6190 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6191 mAppPermissionChangeListeners.add(listener);
6192 }
6193
6194 @Override
6195 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6196 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006197 }
Svet Ganov5d09c992016-09-07 09:57:41 -07006198
6199 @Override
6200 public byte[] backupAccountAccessPermissions(int userId) {
6201 synchronized (mLock) {
6202 if (mBackupHelper == null) {
6203 mBackupHelper = new AccountManagerBackupHelper(
6204 AccountManagerService.this, this);
6205 }
6206 return mBackupHelper.backupAccountAccessPermissions(userId);
6207 }
6208 }
6209
6210 @Override
6211 public void restoreAccountAccessPermissions(byte[] data, int userId) {
6212 synchronized (mLock) {
6213 if (mBackupHelper == null) {
6214 mBackupHelper = new AccountManagerBackupHelper(
6215 AccountManagerService.this, this);
6216 }
6217 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6218 }
6219 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006220 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07006221
6222 @VisibleForTesting
6223 static class Injector {
6224 private final Context mContext;
6225
6226 public Injector(Context context) {
6227 mContext = context;
6228 }
6229
6230 Looper getMessageHandlerLooper() {
6231 ServiceThread serviceThread = new ServiceThread(TAG,
6232 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6233 serviceThread.start();
6234 return serviceThread.getLooper();
6235 }
6236
6237 Context getContext() {
6238 return mContext;
6239 }
6240
6241 void addLocalService(AccountManagerInternal service) {
6242 LocalServices.addService(AccountManagerInternal.class, service);
6243 }
6244
6245 String getDeDatabaseName(int userId) {
6246 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6247 AccountsDb.DE_DATABASE_NAME);
6248 return databaseFile.getPath();
6249 }
6250
6251 String getCeDatabaseName(int userId) {
6252 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6253 AccountsDb.CE_DATABASE_NAME);
6254 return databaseFile.getPath();
6255 }
6256
6257 String getPreNDatabaseName(int userId) {
6258 File systemDir = Environment.getDataSystemDirectory();
6259 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6260 PRE_N_DATABASE_NAME);
6261 if (userId == 0) {
6262 // Migrate old file, if it exists, to the new location.
6263 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006264 // accidentally created in the old location,
6265 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07006266 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6267 if (oldFile.exists() && !databaseFile.exists()) {
6268 // Check for use directory; create if it doesn't exist, else renameTo will fail
6269 File userDir = Environment.getUserSystemDirectory(userId);
6270 if (!userDir.exists()) {
6271 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006272 throw new IllegalStateException(
6273 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006274 }
6275 }
6276 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006277 throw new IllegalStateException(
6278 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006279 }
6280 }
6281 }
6282 return databaseFile.getPath();
6283 }
6284
6285 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6286 return new AccountAuthenticatorCache(mContext);
6287 }
6288
6289 INotificationManager getNotificationManager() {
6290 return NotificationManager.getService();
6291 }
6292 }
Chris Wren717a8812017-03-31 15:34:39 -04006293
Andrew Scullc7770d62017-05-22 17:49:58 +01006294 private static class NotificationId {
Chris Wren717a8812017-03-31 15:34:39 -04006295 final String mTag;
6296 private final int mId;
6297
6298 NotificationId(String tag, int type) {
6299 mTag = tag;
6300 mId = type;
6301 }
6302 }
Fred Quintana60307342009-03-24 22:48:12 -07006303}