blob: 6b346123e94a7f32149dc8559fae4ffab0dc2584 [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;
25import android.accounts.AuthenticatorDescription;
Amith Yamasani23c8b962013-04-10 13:37:18 -070026import android.accounts.CantAddAccountActivity;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080027import android.accounts.GrantCredentialsPermissionActivity;
28import android.accounts.IAccountAuthenticator;
29import android.accounts.IAccountAuthenticatorResponse;
30import android.accounts.IAccountManager;
31import android.accounts.IAccountManagerResponse;
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070032import android.annotation.NonNull;
Brett Chabot3b4fcbc2011-01-09 13:41:02 -080033import android.app.ActivityManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070034import android.app.ActivityManagerNative;
Amith Yamasani3b458ad2013-04-18 18:40:07 -070035import android.app.AppGlobals;
Svetoslavf3f02ac2015-09-08 14:36:35 -070036import android.app.AppOpsManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070037import android.app.Notification;
38import android.app.NotificationManager;
39import android.app.PendingIntent;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010040import android.app.admin.DevicePolicyManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070041import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070042import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070043import android.content.ContentValues;
44import android.content.Context;
45import android.content.Intent;
46import android.content.IntentFilter;
Fred Quintanab839afc2009-10-14 15:57:28 -070047import android.content.ServiceConnection;
Doug Zongker885cfc232009-10-21 16:52:44 -070048import android.content.pm.ApplicationInfo;
49import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070050import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070051import android.content.pm.PackageManager.NameNotFoundException;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070052import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070053import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070054import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070055import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070056import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070057import android.database.Cursor;
58import android.database.DatabaseUtils;
Fred Quintanaa698f422009-04-08 19:14:54 -070059import android.database.sqlite.SQLiteDatabase;
60import android.database.sqlite.SQLiteOpenHelper;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070061import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070062import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070063import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080064import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070065import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070066import android.os.IBinder;
67import android.os.Looper;
68import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070069import android.os.Parcel;
Amith Yamasani27db4682013-03-30 17:07:47 -070070import android.os.Process;
Fred Quintanaa698f422009-04-08 19:14:54 -070071import android.os.RemoteException;
72import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070073import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070074import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070075import android.text.TextUtils;
76import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070077import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070078import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080079import android.util.SparseArray;
Fred Quintana60307342009-03-24 22:48:12 -070080
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070081import com.android.internal.R;
Amith Yamasani67df64b2012-12-14 12:09:36 -080082import com.android.internal.util.ArrayUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080083import com.android.internal.util.IndentingPrintWriter;
Dianne Hackborn8d044e82013-04-30 17:24:15 -070084import com.android.server.FgThread;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070085import com.google.android.collect.Lists;
86import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070087
Oscar Montemayora8529f62009-11-18 10:14:20 -080088import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -070089import java.io.FileDescriptor;
90import java.io.PrintWriter;
Carlos Valdivia91979be2015-05-22 14:11:35 -070091import java.security.MessageDigest;
92import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070093import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -070094import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -080095import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -070096import java.util.Collection;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070097import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070098import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070099import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800100import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700101import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800102import java.util.Map;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700103import java.util.concurrent.atomic.AtomicInteger;
104import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700105
Fred Quintana60307342009-03-24 22:48:12 -0700106/**
107 * A system service that provides account, password, and authtoken management for all
108 * accounts on the device. Some of these calls are implemented with the help of the corresponding
109 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
110 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700111 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700112 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700113 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700114public class AccountManagerService
115 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800116 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700117 private static final String TAG = "AccountManagerService";
118
Fred Quintana60307342009-03-24 22:48:12 -0700119 private static final String DATABASE_NAME = "accounts.db";
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700120 private static final int DATABASE_VERSION = 8;
121
122 private static final int MAX_DEBUG_DB_SIZE = 64;
Fred Quintana60307342009-03-24 22:48:12 -0700123
124 private final Context mContext;
125
Fred Quintana56285a62010-12-02 14:20:51 -0800126 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700127 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700128 private UserManager mUserManager;
Fred Quintana56285a62010-12-02 14:20:51 -0800129
Fred Quintana60307342009-03-24 22:48:12 -0700130 private final MessageHandler mMessageHandler;
131
132 // Messages that can be sent on mHandler
133 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700134 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700135
Fred Quintana56285a62010-12-02 14:20:51 -0800136 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fred Quintana60307342009-03-24 22:48:12 -0700137
138 private static final String TABLE_ACCOUNTS = "accounts";
139 private static final String ACCOUNTS_ID = "_id";
140 private static final String ACCOUNTS_NAME = "name";
141 private static final String ACCOUNTS_TYPE = "type";
Jason Parks1cd7d0e2009-09-28 14:48:34 -0700142 private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
Fred Quintana60307342009-03-24 22:48:12 -0700143 private static final String ACCOUNTS_PASSWORD = "password";
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700144 private static final String ACCOUNTS_PREVIOUS_NAME = "previous_name";
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800145 private static final String ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS =
146 "last_password_entry_time_millis_epoch";
Fred Quintana60307342009-03-24 22:48:12 -0700147
148 private static final String TABLE_AUTHTOKENS = "authtokens";
149 private static final String AUTHTOKENS_ID = "_id";
150 private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
151 private static final String AUTHTOKENS_TYPE = "type";
152 private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
153
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700154 private static final String TABLE_GRANTS = "grants";
155 private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
156 private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
157 private static final String GRANTS_GRANTEE_UID = "uid";
158
Fred Quintana60307342009-03-24 22:48:12 -0700159 private static final String TABLE_EXTRAS = "extras";
160 private static final String EXTRAS_ID = "_id";
161 private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
162 private static final String EXTRAS_KEY = "key";
163 private static final String EXTRAS_VALUE = "value";
164
165 private static final String TABLE_META = "meta";
166 private static final String META_KEY = "key";
167 private static final String META_VALUE = "value";
168
Amith Yamasani67df64b2012-12-14 12:09:36 -0800169 private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
170
Jason Parks1cd7d0e2009-09-28 14:48:34 -0700171 private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
172 new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
Fred Quintana7be59642009-08-24 18:29:25 -0700173 private static final Intent ACCOUNTS_CHANGED_INTENT;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700174 static {
175 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
176 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
177 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700178
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700179 private static final String COUNT_OF_MATCHING_GRANTS = ""
180 + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
181 + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
182 + " AND " + GRANTS_GRANTEE_UID + "=?"
183 + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
184 + " AND " + ACCOUNTS_NAME + "=?"
185 + " AND " + ACCOUNTS_TYPE + "=?";
186
Fred Quintana56285a62010-12-02 14:20:51 -0800187 private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
188 AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
Carlos Valdivia91979be2015-05-22 14:11:35 -0700189
Fred Quintana56285a62010-12-02 14:20:51 -0800190 private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
191 AUTHTOKENS_AUTHTOKEN};
192
193 private static final String SELECTION_USERDATA_BY_ACCOUNT =
194 EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
195 private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
196
Fred Quintanaa698f422009-04-08 19:14:54 -0700197 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700198 private final AtomicInteger mNotificationIds = new AtomicInteger(1);
199
Amith Yamasani04e0d262012-02-14 11:50:53 -0800200 static class UserAccounts {
201 private final int userId;
202 private final DatabaseHelper openHelper;
203 private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
204 credentialsPermissionNotificationIds =
205 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
206 private final HashMap<Account, Integer> signinRequiredNotificationIds =
207 new HashMap<Account, Integer>();
208 private final Object cacheLock = new Object();
209 /** protected by the {@link #cacheLock} */
Amith Yamasanib483a992012-05-22 13:14:25 -0700210 private final HashMap<String, Account[]> accountCache =
211 new LinkedHashMap<String, Account[]>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800212 /** protected by the {@link #cacheLock} */
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -0800213 private final HashMap<Account, HashMap<String, String>> userDataCache =
Amith Yamasani04e0d262012-02-14 11:50:53 -0800214 new HashMap<Account, HashMap<String, String>>();
215 /** protected by the {@link #cacheLock} */
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -0800216 private final HashMap<Account, HashMap<String, String>> authTokenCache =
Amith Yamasani04e0d262012-02-14 11:50:53 -0800217 new HashMap<Account, HashMap<String, String>>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700218
219 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700220 private final TokenCache accountTokenCaches = new TokenCache();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700221
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700222 /**
223 * protected by the {@link #cacheLock}
224 *
225 * Caches the previous names associated with an account. Previous names
226 * should be cached because we expect that when an Account is renamed,
227 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
228 * want to know if the accounts they care about have been renamed.
229 *
230 * The previous names are wrapped in an {@link AtomicReference} so that
231 * we can distinguish between those accounts with no previous names and
232 * those whose previous names haven't been cached (yet).
233 */
234 private final HashMap<Account, AtomicReference<String>> previousNameCache =
235 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800236
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700237 private int debugDbInsertionPoint = -1;
238 private SQLiteStatement statementForLogging;
239
Amith Yamasani04e0d262012-02-14 11:50:53 -0800240 UserAccounts(Context context, int userId) {
241 this.userId = userId;
242 synchronized (cacheLock) {
243 openHelper = new DatabaseHelper(context, userId);
244 }
245 }
246 }
247
248 private final SparseArray<UserAccounts> mUsers = new SparseArray<UserAccounts>();
249
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700250 private static AtomicReference<AccountManagerService> sThis =
251 new AtomicReference<AccountManagerService>();
Fred Quintana31957f12009-10-21 13:43:10 -0700252 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700253
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700254 /**
255 * This should only be called by system code. One should only call this after the service
256 * has started.
257 * @return a reference to the AccountManagerService instance
258 * @hide
259 */
260 public static AccountManagerService getSingleton() {
261 return sThis.get();
262 }
Fred Quintana60307342009-03-24 22:48:12 -0700263
Fred Quintana56285a62010-12-02 14:20:51 -0800264 public AccountManagerService(Context context) {
265 this(context, context.getPackageManager(), new AccountAuthenticatorCache(context));
Fred Quintana60307342009-03-24 22:48:12 -0700266 }
267
Fred Quintana56285a62010-12-02 14:20:51 -0800268 public AccountManagerService(Context context, PackageManager packageManager,
269 IAccountAuthenticatorCache authenticatorCache) {
Fred Quintana60307342009-03-24 22:48:12 -0700270 mContext = context;
Fred Quintana56285a62010-12-02 14:20:51 -0800271 mPackageManager = packageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700272 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fred Quintana60307342009-03-24 22:48:12 -0700273
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700274 mMessageHandler = new MessageHandler(FgThread.get().getLooper());
Fred Quintana60307342009-03-24 22:48:12 -0700275
Fred Quintana56285a62010-12-02 14:20:51 -0800276 mAuthenticatorCache = authenticatorCache;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800277 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700278
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700279 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800280
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800281 IntentFilter intentFilter = new IntentFilter();
282 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
283 intentFilter.addDataScheme("package");
284 mContext.registerReceiver(new BroadcastReceiver() {
285 @Override
286 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700287 // Don't delete accounts when updating a authenticator's
288 // package.
289 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700290 /* Purging data requires file io, don't block the main thread. This is probably
291 * less than ideal because we are introducing a race condition where old grants
292 * could be exercised until they are purged. But that race condition existed
293 * anyway with the broadcast receiver.
294 *
295 * Ideally, we would completely clear the cache, purge data from the database,
296 * and then rebuild the cache. All under the cache lock. But that change is too
297 * large at this point.
298 */
299 Runnable r = new Runnable() {
300 @Override
301 public void run() {
302 purgeOldGrantsAll();
303 }
304 };
305 new Thread(r).start();
Carlos Valdivia23f58262014-09-05 10:52:41 -0700306 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800307 }
308 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800309
Amith Yamasani13593602012-03-22 16:16:17 -0700310 IntentFilter userFilter = new IntentFilter();
311 userFilter.addAction(Intent.ACTION_USER_REMOVED);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800312 userFilter.addAction(Intent.ACTION_USER_STARTED);
313 mContext.registerReceiverAsUser(new BroadcastReceiver() {
Amith Yamasani13593602012-03-22 16:16:17 -0700314 @Override
315 public void onReceive(Context context, Intent intent) {
Amith Yamasani67df64b2012-12-14 12:09:36 -0800316 String action = intent.getAction();
317 if (Intent.ACTION_USER_REMOVED.equals(action)) {
318 onUserRemoved(intent);
319 } else if (Intent.ACTION_USER_STARTED.equals(action)) {
320 onUserStarted(intent);
321 }
Amith Yamasani13593602012-03-22 16:16:17 -0700322 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800323 }, UserHandle.ALL, userFilter, null, null);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800324 }
325
Dianne Hackborn164371f2013-10-01 19:10:13 -0700326 @Override
327 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
328 throws RemoteException {
329 try {
330 return super.onTransact(code, data, reply, flags);
331 } catch (RuntimeException e) {
332 // The account manager only throws security exceptions, so let's
333 // log all others.
334 if (!(e instanceof SecurityException)) {
335 Slog.wtf(TAG, "Account Manager Crash", e);
336 }
337 throw e;
338 }
339 }
340
Kenny Root26ff6622012-07-30 12:58:03 -0700341 public void systemReady() {
Kenny Root26ff6622012-07-30 12:58:03 -0700342 }
343
Amith Yamasani258848d2012-08-10 17:06:33 -0700344 private UserManager getUserManager() {
345 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700346 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700347 }
348 return mUserManager;
349 }
350
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700351 /**
352 * Validate internal set of accounts against installed authenticators for
353 * given user. Clears cached authenticators before validating.
354 */
355 public void validateAccounts(int userId) {
356 final UserAccounts accounts = getUserAccounts(userId);
357
358 // Invalidate user-specific cache to make sure we catch any
359 // removed authenticators.
360 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
361 }
362
363 /**
364 * Validate internal set of accounts against installed authenticators for
365 * given user. Clear cached authenticators before validating when requested.
366 */
367 private void validateAccountsInternal(
368 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
369 if (invalidateAuthenticatorCache) {
370 mAuthenticatorCache.invalidateCache(accounts.userId);
371 }
372
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700373 final HashSet<AuthenticatorDescription> knownAuth = Sets.newHashSet();
374 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service :
375 mAuthenticatorCache.getAllServices(accounts.userId)) {
376 knownAuth.add(service.type);
377 }
378
Amith Yamasani04e0d262012-02-14 11:50:53 -0800379 synchronized (accounts.cacheLock) {
380 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800381 boolean accountDeleted = false;
382 Cursor cursor = db.query(TABLE_ACCOUNTS,
383 new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
Marvin Paul48fcd4e2014-12-01 18:26:07 -0800384 null, null, null, null, ACCOUNTS_ID);
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800385 try {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800386 accounts.accountCache.clear();
Fred Quintana56285a62010-12-02 14:20:51 -0800387 final HashMap<String, ArrayList<String>> accountNamesByType =
Amith Yamasanib483a992012-05-22 13:14:25 -0700388 new LinkedHashMap<String, ArrayList<String>>();
Fred Quintana56285a62010-12-02 14:20:51 -0800389 while (cursor.moveToNext()) {
390 final long accountId = cursor.getLong(0);
391 final String accountType = cursor.getString(1);
392 final String accountName = cursor.getString(2);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700393
394 if (!knownAuth.contains(AuthenticatorDescription.newKey(accountType))) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700395 Slog.w(TAG, "deleting account " + accountName + " because type "
Fred Quintana56285a62010-12-02 14:20:51 -0800396 + accountType + " no longer has a registered authenticator");
397 db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
398 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700399
400 logRecord(db, DebugDbHelper.ACTION_AUTHENTICATOR_REMOVE, TABLE_ACCOUNTS,
401 accountId, accounts);
402
Fred Quintana56285a62010-12-02 14:20:51 -0800403 final Account account = new Account(accountName, accountType);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800404 accounts.userDataCache.remove(account);
405 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700406 accounts.accountTokenCaches.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -0800407 } else {
408 ArrayList<String> accountNames = accountNamesByType.get(accountType);
409 if (accountNames == null) {
410 accountNames = new ArrayList<String>();
411 accountNamesByType.put(accountType, accountNames);
412 }
413 accountNames.add(accountName);
414 }
415 }
Andy McFadden2f362292012-01-20 14:43:38 -0800416 for (Map.Entry<String, ArrayList<String>> cur
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800417 : accountNamesByType.entrySet()) {
Fred Quintana56285a62010-12-02 14:20:51 -0800418 final String accountType = cur.getKey();
419 final ArrayList<String> accountNames = cur.getValue();
420 final Account[] accountsForType = new Account[accountNames.size()];
421 int i = 0;
422 for (String accountName : accountNames) {
423 accountsForType[i] = new Account(accountName, accountType);
424 ++i;
425 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800426 accounts.accountCache.put(accountType, accountsForType);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800427 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800428 } finally {
429 cursor.close();
430 if (accountDeleted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800431 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800432 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800433 }
434 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700435 }
436
Amith Yamasani04e0d262012-02-14 11:50:53 -0800437 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700438 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -0800439 }
440
441 protected UserAccounts getUserAccounts(int userId) {
442 synchronized (mUsers) {
443 UserAccounts accounts = mUsers.get(userId);
444 if (accounts == null) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700445 accounts = new UserAccounts(mContext, userId);
446 initializeDebugDbSizeAndCompileSqlStatementForLogging(
447 accounts.openHelper.getWritableDatabase(), accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800448 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700449 purgeOldGrants(accounts);
450 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800451 }
452 return accounts;
453 }
454 }
455
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700456 private void purgeOldGrantsAll() {
457 synchronized (mUsers) {
458 for (int i = 0; i < mUsers.size(); i++) {
459 purgeOldGrants(mUsers.valueAt(i));
460 }
461 }
462 }
463
464 private void purgeOldGrants(UserAccounts accounts) {
465 synchronized (accounts.cacheLock) {
466 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
467 final Cursor cursor = db.query(TABLE_GRANTS,
468 new String[]{GRANTS_GRANTEE_UID},
469 null, null, GRANTS_GRANTEE_UID, null, null);
470 try {
471 while (cursor.moveToNext()) {
472 final int uid = cursor.getInt(0);
473 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
474 if (packageExists) {
475 continue;
476 }
477 Log.d(TAG, "deleting grants for UID " + uid
478 + " because its package is no longer installed");
479 db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
480 new String[]{Integer.toString(uid)});
481 }
482 } finally {
483 cursor.close();
484 }
485 }
486 }
487
Amith Yamasani13593602012-03-22 16:16:17 -0700488 private void onUserRemoved(Intent intent) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700489 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Amith Yamasani13593602012-03-22 16:16:17 -0700490 if (userId < 1) return;
491
492 UserAccounts accounts;
493 synchronized (mUsers) {
494 accounts = mUsers.get(userId);
495 mUsers.remove(userId);
496 }
497 if (accounts == null) {
498 File dbFile = new File(getDatabaseName(userId));
499 dbFile.delete();
500 return;
501 }
502
503 synchronized (accounts.cacheLock) {
504 accounts.openHelper.close();
505 File dbFile = new File(getDatabaseName(userId));
506 dbFile.delete();
507 }
508 }
509
Amith Yamasani67df64b2012-12-14 12:09:36 -0800510 private void onUserStarted(Intent intent) {
511 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
512 if (userId < 1) return;
513
514 // Check if there's a shared account that needs to be created as an account
515 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
516 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700517 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700518 int parentUserId = UserManager.isSplitSystemUser()
519 ? mUserManager.getUserInfo(userId).restrictedProfileParentId
520 : UserHandle.USER_SYSTEM;
521 if (parentUserId < 0) {
522 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
523 return;
524 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800525 for (Account sa : sharedAccounts) {
526 if (ArrayUtils.contains(accounts, sa)) continue;
527 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700528 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800529 }
530 }
531
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700532 @Override
533 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700534 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -0700535 }
536
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -0800537 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -0700538 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700539 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -0800540 if (Log.isLoggable(TAG, Log.VERBOSE)) {
541 Log.v(TAG, "getPassword: " + account
542 + ", caller's uid " + Binder.getCallingUid()
543 + ", pid " + Binder.getCallingPid());
544 }
Fred Quintana382601f2010-03-25 12:25:10 -0700545 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000546 int userId = UserHandle.getCallingUserId();
547 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700548 String msg = String.format(
549 "uid %s cannot get secrets for accounts of type: %s",
550 callingUid,
551 account.type);
552 throw new SecurityException(msg);
553 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -0700554 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -0700555 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -0700556 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800557 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700558 } finally {
559 restoreCallingIdentity(identityToken);
560 }
561 }
562
Amith Yamasani04e0d262012-02-14 11:50:53 -0800563 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -0700564 if (account == null) {
565 return null;
566 }
567
Amith Yamasani04e0d262012-02-14 11:50:53 -0800568 synchronized (accounts.cacheLock) {
569 final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800570 Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
571 ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
572 new String[]{account.name, account.type}, null, null, null);
573 try {
574 if (cursor.moveToNext()) {
575 return cursor.getString(0);
576 }
577 return null;
578 } finally {
579 cursor.close();
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700580 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700581 }
582 }
583
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -0800584 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700585 public String getPreviousName(Account account) {
586 if (Log.isLoggable(TAG, Log.VERBOSE)) {
587 Log.v(TAG, "getPreviousName: " + account
588 + ", caller's uid " + Binder.getCallingUid()
589 + ", pid " + Binder.getCallingPid());
590 }
591 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -0700592 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700593 long identityToken = clearCallingIdentity();
594 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -0700595 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700596 return readPreviousNameInternal(accounts, account);
597 } finally {
598 restoreCallingIdentity(identityToken);
599 }
600 }
601
602 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
603 if (account == null) {
604 return null;
605 }
606 synchronized (accounts.cacheLock) {
607 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
608 if (previousNameRef == null) {
609 final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
610 Cursor cursor = db.query(
611 TABLE_ACCOUNTS,
612 new String[]{ ACCOUNTS_PREVIOUS_NAME },
613 ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
614 new String[] { account.name, account.type },
615 null,
616 null,
617 null);
618 try {
619 if (cursor.moveToNext()) {
620 String previousName = cursor.getString(0);
621 previousNameRef = new AtomicReference<String>(previousName);
622 accounts.previousNameCache.put(account, previousNameRef);
623 return previousName;
624 } else {
625 return null;
626 }
627 } finally {
628 cursor.close();
629 }
630 } else {
631 return previousNameRef.get();
632 }
633 }
634 }
635
636 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700637 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700638 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -0800639 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700640 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
641 account, key, callingUid, Binder.getCallingPid());
642 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -0800643 }
Fred Quintana382601f2010-03-25 12:25:10 -0700644 if (account == null) throw new IllegalArgumentException("account is null");
645 if (key == null) throw new IllegalArgumentException("key is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000646 int userId = UserHandle.getCallingUserId();
647 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700648 String msg = String.format(
649 "uid %s cannot get user data for accounts of type: %s",
650 callingUid,
651 account.type);
652 throw new SecurityException(msg);
653 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700654 long identityToken = clearCallingIdentity();
655 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -0700656 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800657 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700658 } finally {
659 restoreCallingIdentity(identityToken);
660 }
661 }
662
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -0800663 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100664 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700665 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -0800666 if (Log.isLoggable(TAG, Log.VERBOSE)) {
667 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100668 + "for user id " + userId
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700669 + "caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -0800670 + ", pid " + Binder.getCallingPid());
671 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100672 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700673 if (isCrossUser(callingUid, userId)) {
674 throw new SecurityException(
675 String.format(
676 "User %s tying to get authenticator types for %s" ,
677 UserHandle.getCallingUserId(),
678 userId));
679 }
680
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700681 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -0700682 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000683 return getAuthenticatorTypesInternal(userId);
684
Fred Quintana26fc5eb2009-04-09 15:05:50 -0700685 } finally {
686 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -0700687 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700688 }
689
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000690 /**
691 * Should only be called inside of a clearCallingIdentity block.
692 */
693 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
694 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
695 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
696 AuthenticatorDescription[] types =
697 new AuthenticatorDescription[authenticatorCollection.size()];
698 int i = 0;
699 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
700 : authenticatorCollection) {
701 types[i] = authenticator.type;
702 i++;
703 }
704 return types;
705 }
706
707
708
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700709 private boolean isCrossUser(int callingUid, int userId) {
710 return (userId != UserHandle.getCallingUserId()
711 && callingUid != Process.myUid()
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100712 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700713 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
714 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100715 }
716
Jatin Lodhia3df7d692013-03-27 10:57:23 -0700717 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -0700718 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700719 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -0800720 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700721 Log.v(TAG, "addAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700722 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -0800723 + ", pid " + Binder.getCallingPid());
724 }
Fred Quintana382601f2010-03-25 12:25:10 -0700725 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000726 int userId = UserHandle.getCallingUserId();
727 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700728 String msg = String.format(
729 "uid %s cannot explicitly add accounts of type: %s",
730 callingUid,
731 account.type);
732 throw new SecurityException(msg);
733 }
Jatin Lodhia3df7d692013-03-27 10:57:23 -0700734 /*
735 * Child users are not allowed to add accounts. Only the accounts that are
736 * shared by the parent profile can be added to child profile.
737 *
738 * TODO: Only allow accounts that were shared to be added by
739 * a limited user.
740 */
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700741
Fred Quintana60307342009-03-24 22:48:12 -0700742 // fails if the account already exists
Fred Quintana26fc5eb2009-04-09 15:05:50 -0700743 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -0700744 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -0700745 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000746 return addAccountInternal(accounts, account, password, extras, false, callingUid);
Fred Quintana60307342009-03-24 22:48:12 -0700747 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -0700748 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -0700749 }
750 }
751
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000752 @Override
753 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700754 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700755 int callingUid = Binder.getCallingUid();
756 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
757 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000758 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700759 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800760 final UserAccounts fromAccounts = getUserAccounts(userFrom);
761 final UserAccounts toAccounts = getUserAccounts(userTo);
762 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000763 if (response != null) {
764 Bundle result = new Bundle();
765 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
766 try {
767 response.onResult(result);
768 } catch (RemoteException e) {
769 Slog.w(TAG, "Failed to report error back to the client." + e);
770 }
771 }
772 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -0800773 }
774
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000775 Slog.d(TAG, "Copying account " + account.name
776 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800777 long identityToken = clearCallingIdentity();
778 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000779 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800780 false /* stripAuthTokenFromResult */, account.name,
781 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -0700782 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800783 protected String toDebugString(long now) {
784 return super.toDebugString(now) + ", getAccountCredentialsForClone"
785 + ", " + account.type;
786 }
787
Carlos Valdivia5bab9da2013-09-29 05:11:56 -0700788 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800789 public void run() throws RemoteException {
790 mAuthenticator.getAccountCredentialsForCloning(this, account);
791 }
792
Carlos Valdivia5bab9da2013-09-29 05:11:56 -0700793 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800794 public void onResult(Bundle result) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000795 if (result != null
796 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
797 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700798 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800799 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -0800800 super.onResult(result);
801 }
802 }
803 }.bind();
804 } finally {
805 restoreCallingIdentity(identityToken);
806 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800807 }
808
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800809 @Override
810 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700811 final int callingUid = Binder.getCallingUid();
812 if (Log.isLoggable(TAG, Log.VERBOSE)) {
813 String msg = String.format(
814 "accountAuthenticated( account: %s, callerUid: %s)",
815 account,
816 callingUid);
817 Log.v(TAG, msg);
818 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800819 if (account == null) {
820 throw new IllegalArgumentException("account is null");
821 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000822 int userId = UserHandle.getCallingUserId();
823 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700824 String msg = String.format(
825 "uid %s cannot notify authentication for accounts of type: %s",
826 callingUid,
827 account.type);
828 throw new SecurityException(msg);
829 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000830
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800831 if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
832 return false;
833 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000834
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -0700835 long identityToken = clearCallingIdentity();
836 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000837 UserAccounts accounts = getUserAccounts(userId);
838 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -0700839 } finally {
840 restoreCallingIdentity(identityToken);
841 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -0700842 }
843
844 private boolean updateLastAuthenticatedTime(Account account) {
845 final UserAccounts accounts = getUserAccountsForCaller();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800846 synchronized (accounts.cacheLock) {
847 final ContentValues values = new ContentValues();
848 values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
849 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
850 int i = db.update(
851 TABLE_ACCOUNTS,
852 values,
853 ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
854 new String[] {
855 account.name, account.type
856 });
857 if (i > 0) {
858 return true;
859 }
860 }
861 return false;
862 }
863
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000864 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700865 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
866 final int parentUserId){
Amith Yamasani67df64b2012-12-14 12:09:36 -0800867 long id = clearCallingIdentity();
868 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000869 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800870 false /* stripAuthTokenFromResult */, account.name,
871 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -0700872 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800873 protected String toDebugString(long now) {
874 return super.toDebugString(now) + ", getAccountCredentialsForClone"
875 + ", " + account.type;
876 }
877
Carlos Valdivia5bab9da2013-09-29 05:11:56 -0700878 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800879 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -0700880 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700881 UserAccounts owner = getUserAccounts(parentUserId);
Amith Yamasani5be347b2013-03-31 17:44:31 -0700882 synchronized (owner.cacheLock) {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700883 for (Account acc : getAccounts(parentUserId,
884 mContext.getOpPackageName())) {
Amith Yamasani5be347b2013-03-31 17:44:31 -0700885 if (acc.equals(account)) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000886 mAuthenticator.addAccountFromCredentials(
887 this, account, accountCredentials);
Amith Yamasani5be347b2013-03-31 17:44:31 -0700888 break;
889 }
890 }
891 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800892 }
893
Carlos Valdivia5bab9da2013-09-29 05:11:56 -0700894 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800895 public void onResult(Bundle result) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +0000896 // TODO: Anything to do if if succedded?
897 // TODO: If it failed: Show error notification? Should we remove the shadow
898 // account to avoid retries?
899 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800900 }
901
Carlos Valdivia5bab9da2013-09-29 05:11:56 -0700902 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800903 public void onError(int errorCode, String errorMessage) {
904 super.onError(errorCode, errorMessage);
905 // TODO: Show error notification to user
906 // TODO: Should we remove the shadow account so that it doesn't keep trying?
907 }
908
909 }.bind();
910 } finally {
911 restoreCallingIdentity(id);
912 }
913 }
914
Amith Yamasani04e0d262012-02-14 11:50:53 -0800915 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700916 Bundle extras, boolean restricted, int callingUid) {
Fred Quintana743dfad2010-07-15 10:59:25 -0700917 if (account == null) {
918 return false;
919 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800920 synchronized (accounts.cacheLock) {
921 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800922 db.beginTransaction();
923 try {
924 long numMatches = DatabaseUtils.longForQuery(db,
925 "select count(*) from " + TABLE_ACCOUNTS
926 + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
927 new String[]{account.name, account.type});
928 if (numMatches > 0) {
929 Log.w(TAG, "insertAccountIntoDatabase: " + account
930 + ", skipping since the account already exists");
931 return false;
932 }
933 ContentValues values = new ContentValues();
934 values.put(ACCOUNTS_NAME, account.name);
935 values.put(ACCOUNTS_TYPE, account.type);
936 values.put(ACCOUNTS_PASSWORD, password);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800937 values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800938 long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
939 if (accountId < 0) {
940 Log.w(TAG, "insertAccountIntoDatabase: " + account
941 + ", skipping the DB insert failed");
942 return false;
943 }
944 if (extras != null) {
945 for (String key : extras.keySet()) {
946 final String value = extras.getString(key);
947 if (insertExtraLocked(db, accountId, key, value) < 0) {
948 Log.w(TAG, "insertAccountIntoDatabase: " + account
949 + ", skipping since insertExtra failed for key " + key);
950 return false;
951 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700952 }
953 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800954 db.setTransactionSuccessful();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700955
956 logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_ACCOUNTS, accountId,
957 accounts, callingUid);
958
Amith Yamasani04e0d262012-02-14 11:50:53 -0800959 insertAccountIntoCacheLocked(accounts, account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800960 } finally {
961 db.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700962 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800963 sendAccountsChangedBroadcast(accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -0700964 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700965 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
966 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -0700967 }
968 return true;
969 }
970
971 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700972 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -0700973 * running, then clone the account too.
974 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700975 *
Amith Yamasani5be347b2013-03-31 17:44:31 -0700976 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700977 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -0700978 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -0700979 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700980 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -0700981 addSharedAccountAsUser(account, user.id);
982 try {
983 if (ActivityManagerNative.getDefault().isUserRunning(user.id, false)) {
984 mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
Fyodor Kupolov06a484a2015-08-21 16:33:20 -0700985 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -0700986 }
987 } catch (RemoteException re) {
988 // Shouldn't happen
989 }
990 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700991 }
992 }
993
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800994 private long insertExtraLocked(SQLiteDatabase db, long accountId, String key, String value) {
Fred Quintana60307342009-03-24 22:48:12 -0700995 ContentValues values = new ContentValues();
996 values.put(EXTRAS_KEY, key);
997 values.put(EXTRAS_ACCOUNTS_ID, accountId);
998 values.put(EXTRAS_VALUE, value);
999 return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
1000 }
1001
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001002 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001003 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001004 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001005 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001006 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1007 Log.v(TAG, "hasFeatures: " + account
1008 + ", response " + response
1009 + ", features " + stringArrayToString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001010 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001011 + ", pid " + Binder.getCallingPid());
1012 }
Fred Quintana382601f2010-03-25 12:25:10 -07001013 if (response == null) throw new IllegalArgumentException("response is null");
1014 if (account == null) throw new IllegalArgumentException("account is null");
1015 if (features == null) throw new IllegalArgumentException("features is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001016 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001017 checkReadAccountsPermitted(callingUid, account.type, userId,
1018 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001019
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001020 long identityToken = clearCallingIdentity();
1021 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001022 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001023 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001024 } finally {
1025 restoreCallingIdentity(identityToken);
1026 }
1027 }
1028
1029 private class TestFeaturesSession extends Session {
1030 private final String[] mFeatures;
1031 private final Account mAccount;
1032
Amith Yamasani04e0d262012-02-14 11:50:53 -08001033 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001034 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001035 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001036 true /* stripAuthTokenFromResult */, account.name,
1037 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001038 mFeatures = features;
1039 mAccount = account;
1040 }
1041
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001042 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001043 public void run() throws RemoteException {
1044 try {
1045 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1046 } catch (RemoteException e) {
1047 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1048 }
1049 }
1050
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001051 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001052 public void onResult(Bundle result) {
1053 IAccountManagerResponse response = getResponseAndClose();
1054 if (response != null) {
1055 try {
1056 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001057 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001058 return;
1059 }
Fred Quintana56285a62010-12-02 14:20:51 -08001060 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1061 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1062 + response);
1063 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001064 final Bundle newResult = new Bundle();
1065 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1066 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1067 response.onResult(newResult);
1068 } catch (RemoteException e) {
1069 // if the caller is dead then there is no one to care about remote exceptions
1070 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1071 Log.v(TAG, "failure while notifying response", e);
1072 }
1073 }
1074 }
1075 }
1076
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001077 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001078 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001079 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001080 + ", " + mAccount
1081 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1082 }
1083 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001084
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001085 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001086 public void renameAccount(
1087 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001088 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001089 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1090 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001091 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001092 + ", pid " + Binder.getCallingPid());
1093 }
1094 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001095 int userId = UserHandle.getCallingUserId();
1096 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001097 String msg = String.format(
1098 "uid %s cannot rename accounts of type: %s",
1099 callingUid,
1100 accountToRename.type);
1101 throw new SecurityException(msg);
1102 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001103 long identityToken = clearCallingIdentity();
1104 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001105 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001106 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001107 Bundle result = new Bundle();
1108 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1109 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
1110 try {
1111 response.onResult(result);
1112 } catch (RemoteException e) {
1113 Log.w(TAG, e.getMessage());
1114 }
1115 } finally {
1116 restoreCallingIdentity(identityToken);
1117 }
1118 }
1119
1120 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001121 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001122 Account resultAccount = null;
1123 /*
1124 * Cancel existing notifications. Let authenticators
1125 * re-post notifications as required. But we don't know if
1126 * the authenticators have bound their notifications to
1127 * now stale account name data.
1128 *
1129 * With a rename api, we might not need to do this anymore but it
1130 * shouldn't hurt.
1131 */
1132 cancelNotification(
1133 getSigninRequiredNotificationId(accounts, accountToRename),
1134 new UserHandle(accounts.userId));
1135 synchronized(accounts.credentialsPermissionNotificationIds) {
1136 for (Pair<Pair<Account, String>, Integer> pair:
1137 accounts.credentialsPermissionNotificationIds.keySet()) {
1138 if (accountToRename.equals(pair.first.first)) {
1139 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1140 cancelNotification(id, new UserHandle(accounts.userId));
1141 }
1142 }
1143 }
1144 synchronized (accounts.cacheLock) {
1145 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
1146 db.beginTransaction();
1147 boolean isSuccessful = false;
1148 Account renamedAccount = new Account(newName, accountToRename.type);
1149 try {
1150 final ContentValues values = new ContentValues();
1151 values.put(ACCOUNTS_NAME, newName);
1152 values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
1153 final long accountId = getAccountIdLocked(db, accountToRename);
1154 if (accountId >= 0) {
1155 final String[] argsAccountId = { String.valueOf(accountId) };
1156 db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
1157 db.setTransactionSuccessful();
1158 isSuccessful = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001159 logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_ACCOUNTS, accountId,
1160 accounts);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001161 }
1162 } finally {
1163 db.endTransaction();
1164 if (isSuccessful) {
1165 /*
1166 * Database transaction was successful. Clean up cached
1167 * data associated with the account in the user profile.
1168 */
1169 insertAccountIntoCacheLocked(accounts, renamedAccount);
1170 /*
1171 * Extract the data and token caches before removing the
1172 * old account to preserve the user data associated with
1173 * the account.
1174 */
1175 HashMap<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1176 HashMap<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
1177 removeAccountFromCacheLocked(accounts, accountToRename);
1178 /*
1179 * Update the cached data associated with the renamed
1180 * account.
1181 */
1182 accounts.userDataCache.put(renamedAccount, tmpData);
1183 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1184 accounts.previousNameCache.put(
1185 renamedAccount,
1186 new AtomicReference<String>(accountToRename.name));
1187 resultAccount = renamedAccount;
1188
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001189 int parentUserId = accounts.userId;
1190 if (canHaveProfile(parentUserId)) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001191 /*
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001192 * Owner or system user account was renamed, rename the account for
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001193 * those users with which the account was shared.
1194 */
1195 List<UserInfo> users = mUserManager.getUsers(true);
1196 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001197 if (user.isRestricted()
1198 && (user.restrictedProfileParentId == parentUserId)) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001199 renameSharedAccountAsUser(accountToRename, newName, user.id);
1200 }
1201 }
1202 }
1203 sendAccountsChangedBroadcast(accounts.userId);
1204 }
1205 }
1206 }
1207 return resultAccount;
1208 }
1209
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001210 private boolean canHaveProfile(final int parentUserId) {
1211 final UserInfo userInfo = mUserManager.getUserInfo(parentUserId);
1212 return userInfo != null && userInfo.canHaveProfile();
1213 }
1214
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001215 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001216 public void removeAccount(IAccountManagerResponse response, Account account,
1217 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001218 removeAccountAsUser(
1219 response,
1220 account,
1221 expectActivityLaunch,
1222 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001223 }
1224
1225 @Override
1226 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001227 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001228 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001229 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1230 Log.v(TAG, "removeAccount: " + account
1231 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001232 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001233 + ", pid " + Binder.getCallingPid()
1234 + ", for user id " + userId);
1235 }
1236 if (response == null) throw new IllegalArgumentException("response is null");
1237 if (account == null) throw new IllegalArgumentException("account is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001238 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001239 if (isCrossUser(callingUid, userId)) {
1240 throw new SecurityException(
1241 String.format(
1242 "User %s tying remove account for %s" ,
1243 UserHandle.getCallingUserId(),
1244 userId));
1245 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001246 /*
1247 * Only the system or authenticator should be allowed to remove accounts for that
1248 * authenticator. This will let users remove accounts (via Settings in the system) but not
1249 * arbitrary applications (like competing authenticators).
1250 */
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001251 UserHandle user = new UserHandle(userId);
1252 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1253 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001254 String msg = String.format(
1255 "uid %s cannot remove accounts of type: %s",
1256 callingUid,
1257 account.type);
1258 throw new SecurityException(msg);
1259 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001260 if (!canUserModifyAccounts(userId)) {
1261 try {
1262 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
1263 "User cannot modify accounts");
1264 } catch (RemoteException re) {
1265 }
1266 return;
1267 }
1268 if (!canUserModifyAccountsForType(userId, account.type)) {
1269 try {
1270 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
1271 "User cannot modify accounts of this type (policy).");
1272 } catch (RemoteException re) {
1273 }
1274 return;
1275 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001276 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001277 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001278 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001279 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001280 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08001281 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001282 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001283 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001284 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001285 }
1286 }
1287 }
1288
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001289 logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
1290
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001291 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001292 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
1293 } finally {
1294 restoreCallingIdentity(identityToken);
1295 }
1296 }
1297
1298 @Override
1299 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001300 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001301 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1302 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001303 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001304 + ", pid " + Binder.getCallingPid());
1305 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001306 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001307 if (account == null) {
1308 /*
1309 * Null accounts should result in returning false, as per
1310 * AccountManage.addAccountExplicitly(...) java doc.
1311 */
1312 Log.e(TAG, "account is null");
1313 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001314 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001315 String msg = String.format(
1316 "uid %s cannot explicitly add accounts of type: %s",
1317 callingUid,
1318 account.type);
1319 throw new SecurityException(msg);
1320 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001321 UserAccounts accounts = getUserAccountsForCaller();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001322 if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
1323 return false;
1324 }
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001325 logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001326 long identityToken = clearCallingIdentity();
1327 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001328 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001329 } finally {
1330 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001331 }
Fred Quintana60307342009-03-24 22:48:12 -07001332 }
1333
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001334 private class RemoveAccountSession extends Session {
1335 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001336 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001337 Account account, boolean expectActivityLaunch) {
1338 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001339 true /* stripAuthTokenFromResult */, account.name,
1340 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001341 mAccount = account;
1342 }
1343
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001344 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001345 protected String toDebugString(long now) {
1346 return super.toDebugString(now) + ", removeAccount"
1347 + ", account " + mAccount;
1348 }
1349
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001350 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001351 public void run() throws RemoteException {
1352 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
1353 }
1354
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001355 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001356 public void onResult(Bundle result) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001357 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
1358 && !result.containsKey(AccountManager.KEY_INTENT)) {
1359 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001360 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001361 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001362 }
1363 IAccountManagerResponse response = getResponseAndClose();
1364 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08001365 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1366 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1367 + response);
1368 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001369 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001370 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001371 try {
1372 response.onResult(result2);
1373 } catch (RemoteException e) {
1374 // ignore
1375 }
1376 }
1377 }
1378 super.onResult(result);
1379 }
1380 }
1381
Amith Yamasani04e0d262012-02-14 11:50:53 -08001382 /* For testing */
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001383 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001384 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001385 }
1386
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001387 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001388 int deleted;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001389 synchronized (accounts.cacheLock) {
1390 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001391 final long accountId = getAccountIdLocked(db, account);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001392 deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
1393 + "=?",
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001394 new String[]{account.name, account.type});
Amith Yamasani04e0d262012-02-14 11:50:53 -08001395 removeAccountFromCacheLocked(accounts, account);
1396 sendAccountsChangedBroadcast(accounts.userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001397
1398 logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_ACCOUNTS, accountId, accounts);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001399 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001400 long id = Binder.clearCallingIdentity();
1401 try {
1402 int parentUserId = accounts.userId;
1403 if (canHaveProfile(parentUserId)) {
1404 // Remove from any restricted profiles that are sharing this account.
Amith Yamasani67df64b2012-12-14 12:09:36 -08001405 List<UserInfo> users = mUserManager.getUsers(true);
1406 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001407 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001408 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001409 }
1410 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001411 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001412 } finally {
1413 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001414 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001415 return (deleted > 0);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001416 }
1417
Maggie Benthalla12fccf2013-03-14 18:02:12 -04001418 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001419 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07001420 int callerUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001421 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1422 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07001423 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08001424 + ", pid " + Binder.getCallingPid());
1425 }
Fred Quintana382601f2010-03-25 12:25:10 -07001426 if (accountType == null) throw new IllegalArgumentException("accountType is null");
1427 if (authToken == null) throw new IllegalArgumentException("authToken is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001428 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001429 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001430 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001431 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001432 synchronized (accounts.cacheLock) {
1433 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001434 db.beginTransaction();
1435 try {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001436 invalidateAuthTokenLocked(accounts, db, accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07001437 invalidateCustomTokenLocked(accounts, accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001438 db.setTransactionSuccessful();
1439 } finally {
1440 db.endTransaction();
1441 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001442 }
Fred Quintana60307342009-03-24 22:48:12 -07001443 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001444 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07001445 }
1446 }
1447
Carlos Valdivia91979be2015-05-22 14:11:35 -07001448 private void invalidateCustomTokenLocked(
1449 UserAccounts accounts,
1450 String accountType,
1451 String authToken) {
1452 if (authToken == null || accountType == null) {
1453 return;
1454 }
1455 // Also wipe out cached token in memory.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001456 accounts.accountTokenCaches.remove(accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07001457 }
1458
Amith Yamasani04e0d262012-02-14 11:50:53 -08001459 private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
1460 String accountType, String authToken) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001461 if (authToken == null || accountType == null) {
1462 return;
1463 }
Fred Quintana33269202009-04-20 16:05:10 -07001464 Cursor cursor = db.rawQuery(
1465 "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
1466 + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
1467 + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
1468 + " FROM " + TABLE_ACCOUNTS
1469 + " JOIN " + TABLE_AUTHTOKENS
1470 + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
1471 + " = " + AUTHTOKENS_ACCOUNTS_ID
1472 + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
1473 + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
1474 new String[]{authToken, accountType});
1475 try {
1476 while (cursor.moveToNext()) {
1477 long authTokenId = cursor.getLong(0);
1478 String accountName = cursor.getString(1);
1479 String authTokenType = cursor.getString(2);
1480 db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
Carlos Valdivia91979be2015-05-22 14:11:35 -07001481 writeAuthTokenIntoCacheLocked(
1482 accounts,
1483 db,
1484 new Account(accountName, accountType),
1485 authTokenType,
1486 null);
Fred Quintana60307342009-03-24 22:48:12 -07001487 }
Fred Quintana33269202009-04-20 16:05:10 -07001488 } finally {
1489 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07001490 }
1491 }
1492
Carlos Valdivia91979be2015-05-22 14:11:35 -07001493 private void saveCachedToken(
1494 UserAccounts accounts,
1495 Account account,
1496 String callerPkg,
1497 byte[] callerSigDigest,
1498 String tokenType,
1499 String token,
1500 long expiryMillis) {
1501
1502 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
1503 return;
1504 }
1505 cancelNotification(getSigninRequiredNotificationId(accounts, account),
1506 new UserHandle(accounts.userId));
1507 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001508 accounts.accountTokenCaches.put(
1509 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07001510 }
1511 }
1512
Amith Yamasani04e0d262012-02-14 11:50:53 -08001513 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
1514 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07001515 if (account == null || type == null) {
1516 return false;
1517 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001518 cancelNotification(getSigninRequiredNotificationId(accounts, account),
1519 new UserHandle(accounts.userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08001520 synchronized (accounts.cacheLock) {
1521 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001522 db.beginTransaction();
1523 try {
1524 long accountId = getAccountIdLocked(db, account);
1525 if (accountId < 0) {
1526 return false;
1527 }
1528 db.delete(TABLE_AUTHTOKENS,
1529 AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
1530 new String[]{type});
1531 ContentValues values = new ContentValues();
1532 values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
1533 values.put(AUTHTOKENS_TYPE, type);
1534 values.put(AUTHTOKENS_AUTHTOKEN, authToken);
1535 if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
1536 db.setTransactionSuccessful();
Amith Yamasani04e0d262012-02-14 11:50:53 -08001537 writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001538 return true;
1539 }
Fred Quintana33269202009-04-20 16:05:10 -07001540 return false;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001541 } finally {
1542 db.endTransaction();
Fred Quintana33269202009-04-20 16:05:10 -07001543 }
Fred Quintana60307342009-03-24 22:48:12 -07001544 }
1545 }
1546
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001547 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001548 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001549 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001550 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1551 Log.v(TAG, "peekAuthToken: " + account
1552 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001553 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001554 + ", pid " + Binder.getCallingPid());
1555 }
Fred Quintana382601f2010-03-25 12:25:10 -07001556 if (account == null) throw new IllegalArgumentException("account is null");
1557 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001558 int userId = UserHandle.getCallingUserId();
1559 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001560 String msg = String.format(
1561 "uid %s cannot peek the authtokens associated with accounts of type: %s",
1562 callingUid,
1563 account.type);
1564 throw new SecurityException(msg);
1565 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001566 long identityToken = clearCallingIdentity();
1567 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001568 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001569 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001570 } finally {
1571 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07001572 }
Fred Quintana60307342009-03-24 22:48:12 -07001573 }
1574
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001575 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001576 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001577 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001578 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1579 Log.v(TAG, "setAuthToken: " + account
1580 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001581 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001582 + ", pid " + Binder.getCallingPid());
1583 }
Fred Quintana382601f2010-03-25 12:25:10 -07001584 if (account == null) throw new IllegalArgumentException("account is null");
1585 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001586 int userId = UserHandle.getCallingUserId();
1587 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001588 String msg = String.format(
1589 "uid %s cannot set auth tokens associated with accounts of type: %s",
1590 callingUid,
1591 account.type);
1592 throw new SecurityException(msg);
1593 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001594 long identityToken = clearCallingIdentity();
1595 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001596 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001597 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001598 } finally {
1599 restoreCallingIdentity(identityToken);
1600 }
Fred Quintana60307342009-03-24 22:48:12 -07001601 }
1602
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001603 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001604 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001605 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001606 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1607 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001608 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001609 + ", pid " + Binder.getCallingPid());
1610 }
Fred Quintana382601f2010-03-25 12:25:10 -07001611 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001612 int userId = UserHandle.getCallingUserId();
1613 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001614 String msg = String.format(
1615 "uid %s cannot set secrets for accounts of type: %s",
1616 callingUid,
1617 account.type);
1618 throw new SecurityException(msg);
1619 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001620 long identityToken = clearCallingIdentity();
1621 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001622 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001623 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001624 } finally {
1625 restoreCallingIdentity(identityToken);
1626 }
Fred Quintana60307342009-03-24 22:48:12 -07001627 }
1628
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001629 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
1630 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07001631 if (account == null) {
1632 return;
1633 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001634 synchronized (accounts.cacheLock) {
1635 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001636 db.beginTransaction();
1637 try {
1638 final ContentValues values = new ContentValues();
1639 values.put(ACCOUNTS_PASSWORD, password);
1640 final long accountId = getAccountIdLocked(db, account);
1641 if (accountId >= 0) {
1642 final String[] argsAccountId = {String.valueOf(accountId)};
1643 db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
1644 db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001645 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07001646 accounts.accountTokenCaches.remove(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001647 db.setTransactionSuccessful();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001648
1649 String action = (password == null || password.length() == 0) ?
1650 DebugDbHelper.ACTION_CLEAR_PASSWORD
1651 : DebugDbHelper.ACTION_SET_PASSWORD;
1652 logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts, callingUid);
Costin Manolachef5ffe892011-01-19 09:35:32 -08001653 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001654 } finally {
1655 db.endTransaction();
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08001656 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001657 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08001658 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001659 }
1660
Amith Yamasani04e0d262012-02-14 11:50:53 -08001661 private void sendAccountsChangedBroadcast(int userId) {
Fred Quintana56285a62010-12-02 14:20:51 -08001662 Log.i(TAG, "the accounts changed, sending broadcast of "
1663 + ACCOUNTS_CHANGED_INTENT.getAction());
Dianne Hackborn79af1dd2012-08-16 16:42:52 -07001664 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Fred Quintana33269202009-04-20 16:05:10 -07001665 }
1666
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001667 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001668 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001669 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001670 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1671 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001672 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001673 + ", pid " + Binder.getCallingPid());
1674 }
Fred Quintana382601f2010-03-25 12:25:10 -07001675 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001676 int userId = UserHandle.getCallingUserId();
1677 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001678 String msg = String.format(
1679 "uid %s cannot clear passwords for accounts of type: %s",
1680 callingUid,
1681 account.type);
1682 throw new SecurityException(msg);
1683 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001684 long identityToken = clearCallingIdentity();
1685 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001686 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001687 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001688 } finally {
1689 restoreCallingIdentity(identityToken);
1690 }
Fred Quintana60307342009-03-24 22:48:12 -07001691 }
1692
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001693 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001694 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001695 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001696 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1697 Log.v(TAG, "setUserData: " + account
1698 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001699 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001700 + ", pid " + Binder.getCallingPid());
1701 }
Fred Quintana382601f2010-03-25 12:25:10 -07001702 if (key == null) throw new IllegalArgumentException("key is null");
1703 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001704 int userId = UserHandle.getCallingUserId();
1705 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001706 String msg = String.format(
1707 "uid %s cannot set user data for accounts of type: %s",
1708 callingUid,
1709 account.type);
1710 throw new SecurityException(msg);
1711 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001712 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001713 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001714 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001715 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07001716 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001717 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07001718 }
1719 }
1720
Amith Yamasani04e0d262012-02-14 11:50:53 -08001721 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
1722 String value) {
Fred Quintana31957f12009-10-21 13:43:10 -07001723 if (account == null || key == null) {
1724 return;
1725 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001726 synchronized (accounts.cacheLock) {
1727 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001728 db.beginTransaction();
1729 try {
1730 long accountId = getAccountIdLocked(db, account);
1731 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001732 return;
1733 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001734 long extrasId = getExtrasIdLocked(db, accountId, key);
1735 if (extrasId < 0 ) {
1736 extrasId = insertExtraLocked(db, accountId, key, value);
1737 if (extrasId < 0) {
1738 return;
1739 }
1740 } else {
1741 ContentValues values = new ContentValues();
1742 values.put(EXTRAS_VALUE, value);
1743 if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
1744 return;
1745 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001746
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001747 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001748 writeUserDataIntoCacheLocked(accounts, db, account, key, value);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001749 db.setTransactionSuccessful();
1750 } finally {
1751 db.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001752 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001753 }
1754 }
1755
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001756 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08001757 if (result == null) {
1758 Log.e(TAG, "the result is unexpectedly null", new Exception());
1759 }
1760 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1761 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1762 + response);
1763 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001764 try {
1765 response.onResult(result);
1766 } catch (RemoteException e) {
1767 // if the caller is dead then there is no one to care about remote
1768 // exceptions
1769 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1770 Log.v(TAG, "failure while notifying response", e);
1771 }
1772 }
1773 }
1774
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001775 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07001776 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
1777 final String authTokenType)
1778 throws RemoteException {
1779 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08001780 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1781
Fred Quintanad9640ec2012-05-23 12:37:00 -07001782 final int callingUid = getCallingUid();
1783 clearCallingIdentity();
Amith Yamasani27db4682013-03-30 17:07:47 -07001784 if (callingUid != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07001785 throw new SecurityException("can only call from system");
1786 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001787 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08001788 long identityToken = clearCallingIdentity();
1789 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001790 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001791 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
1792 false /* stripAuthTokenFromResult */, null /* accountName */,
1793 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001794 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08001795 protected String toDebugString(long now) {
1796 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07001797 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08001798 + ", authTokenType " + authTokenType;
1799 }
1800
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001801 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08001802 public void run() throws RemoteException {
1803 mAuthenticator.getAuthTokenLabel(this, authTokenType);
1804 }
1805
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001806 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08001807 public void onResult(Bundle result) {
1808 if (result != null) {
1809 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
1810 Bundle bundle = new Bundle();
1811 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
1812 super.onResult(bundle);
1813 return;
1814 } else {
1815 super.onResult(result);
1816 }
1817 }
1818 }.bind();
1819 } finally {
1820 restoreCallingIdentity(identityToken);
1821 }
1822 }
1823
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001824 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07001825 public void getAuthToken(
1826 IAccountManagerResponse response,
1827 final Account account,
1828 final String authTokenType,
1829 final boolean notifyOnAuthFailure,
1830 final boolean expectActivityLaunch,
1831 final Bundle loginOptions) {
Fred Quintana56285a62010-12-02 14:20:51 -08001832 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1833 Log.v(TAG, "getAuthToken: " + account
1834 + ", response " + response
1835 + ", authTokenType " + authTokenType
1836 + ", notifyOnAuthFailure " + notifyOnAuthFailure
1837 + ", expectActivityLaunch " + expectActivityLaunch
1838 + ", caller's uid " + Binder.getCallingUid()
1839 + ", pid " + Binder.getCallingPid());
1840 }
Fred Quintana382601f2010-03-25 12:25:10 -07001841 if (response == null) throw new IllegalArgumentException("response is null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001842 try {
1843 if (account == null) {
1844 Slog.w(TAG, "getAuthToken called with null account");
1845 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
1846 return;
1847 }
1848 if (authTokenType == null) {
1849 Slog.w(TAG, "getAuthToken called with null authTokenType");
1850 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
1851 return;
1852 }
1853 } catch (RemoteException e) {
1854 Slog.w(TAG, "Failed to report error back to the client." + e);
1855 return;
1856 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001857 int userId = UserHandle.getCallingUserId();
1858 long ident = Binder.clearCallingIdentity();
1859 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001860 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001861 try {
1862 accounts = getUserAccounts(userId);
1863 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
1864 AuthenticatorDescription.newKey(account.type), accounts.userId);
1865 } finally {
1866 Binder.restoreCallingIdentity(ident);
1867 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07001868
Costin Manolachea40c6302010-12-13 14:50:45 -08001869 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07001870 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08001871
1872 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001873 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001874 final boolean permissionGranted =
1875 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08001876
Carlos Valdivia91979be2015-05-22 14:11:35 -07001877 // Get the calling package. We will use it for the purpose of caching.
1878 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07001879 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001880 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07001881 try {
1882 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
1883 } finally {
1884 Binder.restoreCallingIdentity(ident);
1885 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07001886 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
1887 String msg = String.format(
1888 "Uid %s is attempting to illegally masquerade as package %s!",
1889 callerUid,
1890 callerPkg);
1891 throw new SecurityException(msg);
1892 }
1893
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001894 // let authenticator know the identity of the caller
1895 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
1896 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07001897
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001898 if (notifyOnAuthFailure) {
1899 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08001900 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001901
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001902 long identityToken = clearCallingIdentity();
1903 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07001904 // Distill the caller's package signatures into a single digest.
1905 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
1906
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001907 // if the caller has permission, do the peek. otherwise go the more expensive
1908 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08001909 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001910 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001911 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001912 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001913 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
1914 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
1915 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001916 onResult(response, result);
1917 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07001918 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001919 }
1920
Carlos Valdivia91979be2015-05-22 14:11:35 -07001921 if (customTokens) {
1922 /*
1923 * Look up tokens in the new cache only if the loginOptions don't have parameters
1924 * outside of those expected to be injected by the AccountManager, e.g.
1925 * ANDORID_PACKAGE_NAME.
1926 */
1927 String token = readCachedTokenInternal(
1928 accounts,
1929 account,
1930 authTokenType,
1931 callerPkg,
1932 callerPkgSigDigest);
1933 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001934 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1935 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
1936 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07001937 Bundle result = new Bundle();
1938 result.putString(AccountManager.KEY_AUTHTOKEN, token);
1939 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
1940 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
1941 onResult(response, result);
1942 return;
1943 }
1944 }
1945
Amith Yamasani04e0d262012-02-14 11:50:53 -08001946 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001947 false /* stripAuthTokenFromResult */, account.name,
1948 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001949 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001950 protected String toDebugString(long now) {
1951 if (loginOptions != null) loginOptions.keySet();
1952 return super.toDebugString(now) + ", getAuthToken"
1953 + ", " + account
1954 + ", authTokenType " + authTokenType
1955 + ", loginOptions " + loginOptions
1956 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
1957 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001958
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001959 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001960 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001961 // If the caller doesn't have permission then create and return the
1962 // "grant permission" intent instead of the "getAuthToken" intent.
1963 if (!permissionGranted) {
1964 mAuthenticator.getAuthTokenLabel(this, authTokenType);
1965 } else {
1966 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
1967 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001968 }
1969
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001970 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001971 public void onResult(Bundle result) {
1972 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001973 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001974 Intent intent = newGrantCredentialsPermissionIntent(
1975 account,
1976 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001977 new AccountAuthenticatorResponse(this),
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001978 authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001979 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001980 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001981 onResult(bundle);
1982 return;
1983 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001984 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001985 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001986 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1987 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001988 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001989 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001990 "the type and name should not be empty");
1991 return;
1992 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07001993 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08001994 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07001995 saveAuthTokenToDatabase(
1996 mAccounts,
1997 resultAccount,
1998 authTokenType,
1999 authToken);
2000 }
2001 long expiryMillis = result.getLong(
2002 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2003 if (customTokens
2004 && expiryMillis > System.currentTimeMillis()) {
2005 saveCachedToken(
2006 mAccounts,
2007 account,
2008 callerPkg,
2009 callerPkgSigDigest,
2010 authTokenType,
2011 authToken,
2012 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002013 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002014 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002015
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002016 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002017 if (intent != null && notifyOnAuthFailure && !customTokens) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002018 doNotification(mAccounts,
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002019 account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Dianne Hackborn41203752012-08-31 14:05:51 -07002020 intent, accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002021 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002022 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002023 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002024 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002025 }.bind();
2026 } finally {
2027 restoreCallingIdentity(identityToken);
2028 }
Fred Quintana60307342009-03-24 22:48:12 -07002029 }
2030
Carlos Valdivia91979be2015-05-22 14:11:35 -07002031 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2032 MessageDigest digester;
2033 try {
2034 digester = MessageDigest.getInstance("SHA-256");
2035 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2036 callerPkg, PackageManager.GET_SIGNATURES);
2037 for (Signature sig : pkgInfo.signatures) {
2038 digester.update(sig.toByteArray());
2039 }
2040 } catch (NoSuchAlgorithmException x) {
2041 Log.wtf(TAG, "SHA-256 should be available", x);
2042 digester = null;
2043 } catch (NameNotFoundException e) {
2044 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2045 digester = null;
2046 }
2047 return (digester == null) ? null : digester.digest();
2048 }
2049
Dianne Hackborn41203752012-08-31 14:05:51 -07002050 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
2051 int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002052 int uid = intent.getIntExtra(
2053 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2054 String authTokenType = intent.getStringExtra(
2055 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002056 final String titleAndSubtitle =
2057 mContext.getString(R.string.permission_request_notification_with_subtitle,
2058 account.name);
2059 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002060 String title = titleAndSubtitle;
2061 String subtitle = "";
2062 if (index > 0) {
2063 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002064 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002065 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002066 UserHandle user = new UserHandle(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002067 Context contextForUser = getContextForUser(user);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002068 Notification n = new Notification.Builder(contextForUser)
2069 .setSmallIcon(android.R.drawable.stat_sys_warning)
2070 .setWhen(0)
2071 .setColor(contextForUser.getColor(
2072 com.android.internal.R.color.system_notification_accent_color))
2073 .setContentTitle(title)
2074 .setContentText(subtitle)
2075 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2076 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2077 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002078 installNotification(getCredentialPermissionNotificationId(
2079 account, authTokenType, uid), n, user);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002080 }
2081
Costin Manolache5f383ad92010-12-02 16:44:46 -08002082 private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002083 AccountAuthenticatorResponse response, String authTokenType) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002084
2085 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Brian Carlstrom46703b02011-04-06 15:41:29 -07002086 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
Costin Manolache9ec17362011-01-17 12:12:37 -08002087 // Since it was set in Eclair+ we can't change it without breaking apps using
2088 // the intent from a non-Activity context.
2089 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002090 intent.addCategory(
2091 String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
Costin Manolache5f383ad92010-12-02 16:44:46 -08002092
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002093 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002094 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2095 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002096 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002097
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002098 return intent;
2099 }
2100
2101 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2102 int uid) {
2103 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002104 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002105 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002106 final Pair<Pair<Account, String>, Integer> key =
2107 new Pair<Pair<Account, String>, Integer>(
2108 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002109 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002110 if (id == null) {
2111 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002112 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002113 }
2114 }
2115 return id;
2116 }
2117
Amith Yamasani04e0d262012-02-14 11:50:53 -08002118 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002119 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002120 synchronized (accounts.signinRequiredNotificationIds) {
2121 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002122 if (id == null) {
2123 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002124 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002125 }
2126 }
2127 return id;
2128 }
2129
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002130 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002131 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002132 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002133 final boolean expectActivityLaunch, final Bundle optionsIn) {
Fred Quintana56285a62010-12-02 14:20:51 -08002134 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2135 Log.v(TAG, "addAccount: accountType " + accountType
2136 + ", response " + response
2137 + ", authTokenType " + authTokenType
2138 + ", requiredFeatures " + stringArrayToString(requiredFeatures)
2139 + ", expectActivityLaunch " + expectActivityLaunch
2140 + ", caller's uid " + Binder.getCallingUid()
2141 + ", pid " + Binder.getCallingPid());
2142 }
Fred Quintana382601f2010-03-25 12:25:10 -07002143 if (response == null) throw new IllegalArgumentException("response is null");
2144 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002145
Amith Yamasani71e6c692013-03-24 17:39:28 -07002146 // Is user disallowed from modifying accounts?
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002147 int userId = Binder.getCallingUserHandle().getIdentifier();
2148 if (!canUserModifyAccounts(userId)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002149 try {
2150 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2151 "User is not allowed to add an account!");
2152 } catch (RemoteException re) {
2153 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002154 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002155 return;
2156 }
2157 if (!canUserModifyAccountsForType(userId, accountType)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002158 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002159 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2160 "User cannot modify accounts of this type (policy).");
2161 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002162 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002163 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2164 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002165 return;
2166 }
2167
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002168 final int pid = Binder.getCallingPid();
2169 final int uid = Binder.getCallingUid();
2170 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2171 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2172 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2173
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002174 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002175 long identityToken = clearCallingIdentity();
2176 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002177 UserAccounts accounts = getUserAccounts(usrId);
2178 logRecordWithUid(
2179 accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002180 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002181 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002182 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002183 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002184 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07002185 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07002186 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002187 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002188
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002189 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002190 protected String toDebugString(long now) {
2191 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07002192 + ", accountType " + accountType
2193 + ", requiredFeatures "
2194 + (requiredFeatures != null
2195 ? TextUtils.join(",", requiredFeatures)
2196 : null);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002197 }
2198 }.bind();
2199 } finally {
2200 restoreCallingIdentity(identityToken);
2201 }
Fred Quintana60307342009-03-24 22:48:12 -07002202 }
2203
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002204 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002205 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
2206 final String authTokenType, final String[] requiredFeatures,
2207 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002208 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002209 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2210 Log.v(TAG, "addAccount: accountType " + accountType
2211 + ", response " + response
2212 + ", authTokenType " + authTokenType
2213 + ", requiredFeatures " + stringArrayToString(requiredFeatures)
2214 + ", expectActivityLaunch " + expectActivityLaunch
2215 + ", caller's uid " + Binder.getCallingUid()
2216 + ", pid " + Binder.getCallingPid()
2217 + ", for user id " + userId);
2218 }
2219 if (response == null) throw new IllegalArgumentException("response is null");
2220 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002221 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002222 if (isCrossUser(callingUid, userId)) {
2223 throw new SecurityException(
2224 String.format(
2225 "User %s trying to add account for %s" ,
2226 UserHandle.getCallingUserId(),
2227 userId));
2228 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002229
2230 // Is user disallowed from modifying accounts?
2231 if (!canUserModifyAccounts(userId)) {
2232 try {
2233 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2234 "User is not allowed to add an account!");
2235 } catch (RemoteException re) {
2236 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002237 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002238 return;
2239 }
2240 if (!canUserModifyAccountsForType(userId, accountType)) {
2241 try {
2242 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2243 "User cannot modify accounts of this type (policy).");
2244 } catch (RemoteException re) {
2245 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002246 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2247 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002248 return;
2249 }
2250
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002251 final int pid = Binder.getCallingPid();
2252 final int uid = Binder.getCallingUid();
2253 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2254 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2255 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2256
2257 long identityToken = clearCallingIdentity();
2258 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002259 UserAccounts accounts = getUserAccounts(userId);
2260 logRecordWithUid(
2261 accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002262 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002263 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002264 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002265 @Override
2266 public void run() throws RemoteException {
2267 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
2268 options);
2269 }
2270
2271 @Override
2272 protected String toDebugString(long now) {
2273 return super.toDebugString(now) + ", addAccount"
2274 + ", accountType " + accountType
2275 + ", requiredFeatures "
2276 + (requiredFeatures != null
2277 ? TextUtils.join(",", requiredFeatures)
2278 : null);
2279 }
2280 }.bind();
2281 } finally {
2282 restoreCallingIdentity(identityToken);
2283 }
2284 }
2285
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002286 private void showCantAddAccount(int errorCode, int userId) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002287 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
2288 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
2289 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2290 long identityToken = clearCallingIdentity();
2291 try {
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002292 mContext.startActivityAsUser(cantAddAccount, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002293 } finally {
2294 restoreCallingIdentity(identityToken);
2295 }
2296 }
2297
2298 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002299 public void confirmCredentialsAsUser(
2300 IAccountManagerResponse response,
2301 final Account account,
2302 final Bundle options,
2303 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002304 int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002305 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002306 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2307 Log.v(TAG, "confirmCredentials: " + account
2308 + ", response " + response
2309 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002310 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002311 + ", pid " + Binder.getCallingPid());
2312 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002313 // Only allow the system process to read accounts of other users
2314 if (isCrossUser(callingUid, userId)) {
2315 throw new SecurityException(
2316 String.format(
2317 "User %s trying to confirm account credentials for %s" ,
2318 UserHandle.getCallingUserId(),
2319 userId));
2320 }
Fred Quintana382601f2010-03-25 12:25:10 -07002321 if (response == null) throw new IllegalArgumentException("response is null");
2322 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002323 long identityToken = clearCallingIdentity();
2324 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002325 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002326 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002327 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07002328 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002329 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002330 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002331 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002332 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002333 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002334 protected String toDebugString(long now) {
2335 return super.toDebugString(now) + ", confirmCredentials"
2336 + ", " + account;
2337 }
2338 }.bind();
2339 } finally {
2340 restoreCallingIdentity(identityToken);
2341 }
Fred Quintana60307342009-03-24 22:48:12 -07002342 }
2343
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002344 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002345 public void updateCredentials(IAccountManagerResponse response, final Account account,
2346 final String authTokenType, final boolean expectActivityLaunch,
2347 final Bundle loginOptions) {
Fred Quintana56285a62010-12-02 14:20:51 -08002348 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2349 Log.v(TAG, "updateCredentials: " + account
2350 + ", response " + response
2351 + ", authTokenType " + authTokenType
2352 + ", expectActivityLaunch " + expectActivityLaunch
2353 + ", caller's uid " + Binder.getCallingUid()
2354 + ", pid " + Binder.getCallingPid());
2355 }
Fred Quintana382601f2010-03-25 12:25:10 -07002356 if (response == null) throw new IllegalArgumentException("response is null");
2357 if (account == null) throw new IllegalArgumentException("account is null");
2358 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002359 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002360 long identityToken = clearCallingIdentity();
2361 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002362 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002363 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002364 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07002365 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002366 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002367 public void run() throws RemoteException {
2368 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
2369 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002370 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002371 protected String toDebugString(long now) {
2372 if (loginOptions != null) loginOptions.keySet();
2373 return super.toDebugString(now) + ", updateCredentials"
2374 + ", " + account
2375 + ", authTokenType " + authTokenType
2376 + ", loginOptions " + loginOptions;
2377 }
2378 }.bind();
2379 } finally {
2380 restoreCallingIdentity(identityToken);
2381 }
Fred Quintana60307342009-03-24 22:48:12 -07002382 }
2383
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002384 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002385 public void editProperties(IAccountManagerResponse response, final String accountType,
2386 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002387 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002388 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2389 Log.v(TAG, "editProperties: accountType " + accountType
2390 + ", response " + response
2391 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002392 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002393 + ", pid " + Binder.getCallingPid());
2394 }
Fred Quintana382601f2010-03-25 12:25:10 -07002395 if (response == null) throw new IllegalArgumentException("response is null");
2396 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002397 int userId = UserHandle.getCallingUserId();
2398 if (!isAccountManagedByCaller(accountType, callingUid, userId) && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002399 String msg = String.format(
2400 "uid %s cannot edit authenticator properites for account type: %s",
2401 callingUid,
2402 accountType);
2403 throw new SecurityException(msg);
2404 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002405 long identityToken = clearCallingIdentity();
2406 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002407 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002408 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002409 true /* stripAuthTokenFromResult */, null /* accountName */,
2410 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002411 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002412 public void run() throws RemoteException {
2413 mAuthenticator.editProperties(this, mAccountType);
2414 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002415 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002416 protected String toDebugString(long now) {
2417 return super.toDebugString(now) + ", editProperties"
2418 + ", accountType " + accountType;
2419 }
2420 }.bind();
2421 } finally {
2422 restoreCallingIdentity(identityToken);
2423 }
Fred Quintana60307342009-03-24 22:48:12 -07002424 }
2425
Fred Quintana33269202009-04-20 16:05:10 -07002426 private class GetAccountsByTypeAndFeatureSession extends Session {
2427 private final String[] mFeatures;
2428 private volatile Account[] mAccountsOfType = null;
2429 private volatile ArrayList<Account> mAccountsWithFeatures = null;
2430 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002431 private final int mCallingUid;
Fred Quintana33269202009-04-20 16:05:10 -07002432
Amith Yamasani04e0d262012-02-14 11:50:53 -08002433 public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002434 IAccountManagerResponse response, String type, String[] features, int callingUid) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002435 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002436 true /* stripAuthTokenFromResult */, null /* accountName */,
2437 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002438 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07002439 mFeatures = features;
2440 }
2441
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002442 @Override
Fred Quintana33269202009-04-20 16:05:10 -07002443 public void run() throws RemoteException {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002444 synchronized (mAccounts.cacheLock) {
Amith Yamasani27db4682013-03-30 17:07:47 -07002445 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
2446 null);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002447 }
Fred Quintana33269202009-04-20 16:05:10 -07002448 // check whether each account matches the requested features
2449 mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
2450 mCurrentAccount = 0;
2451
2452 checkAccount();
2453 }
2454
2455 public void checkAccount() {
2456 if (mCurrentAccount >= mAccountsOfType.length) {
2457 sendResult();
2458 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002459 }
Fred Quintana33269202009-04-20 16:05:10 -07002460
Fred Quintana29e94b82010-03-10 12:11:51 -08002461 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
2462 if (accountAuthenticator == null) {
2463 // It is possible that the authenticator has died, which is indicated by
2464 // mAuthenticator being set to null. If this happens then just abort.
2465 // There is no need to send back a result or error in this case since
2466 // that already happened when mAuthenticator was cleared.
2467 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2468 Log.v(TAG, "checkAccount: aborting session since we are no longer"
2469 + " connected to the authenticator, " + toDebugString());
2470 }
2471 return;
2472 }
Fred Quintana33269202009-04-20 16:05:10 -07002473 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08002474 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07002475 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002476 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07002477 }
2478 }
2479
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002480 @Override
Fred Quintana33269202009-04-20 16:05:10 -07002481 public void onResult(Bundle result) {
2482 mNumResults++;
2483 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002484 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07002485 return;
2486 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002487 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07002488 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
2489 }
2490 mCurrentAccount++;
2491 checkAccount();
2492 }
2493
2494 public void sendResult() {
2495 IAccountManagerResponse response = getResponseAndClose();
2496 if (response != null) {
2497 try {
2498 Account[] accounts = new Account[mAccountsWithFeatures.size()];
2499 for (int i = 0; i < accounts.length; i++) {
2500 accounts[i] = mAccountsWithFeatures.get(i);
2501 }
Fred Quintana56285a62010-12-02 14:20:51 -08002502 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2503 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2504 + response);
2505 }
Fred Quintana33269202009-04-20 16:05:10 -07002506 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002507 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07002508 response.onResult(result);
2509 } catch (RemoteException e) {
2510 // if the caller is dead then there is no one to care about remote exceptions
2511 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2512 Log.v(TAG, "failure while notifying response", e);
2513 }
2514 }
2515 }
2516 }
2517
2518
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002519 @Override
Fred Quintana33269202009-04-20 16:05:10 -07002520 protected String toDebugString(long now) {
2521 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
2522 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
2523 }
2524 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002525
Amith Yamasani04e0d262012-02-14 11:50:53 -08002526 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002527 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08002528 * @hide
2529 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002530 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07002531 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002532 int callingUid = Binder.getCallingUid();
Svetoslavf3f02ac2015-09-08 14:36:35 -07002533 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
2534 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002535 if (visibleAccountTypes.isEmpty()) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002536 return new Account[0];
2537 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08002538 long identityToken = clearCallingIdentity();
2539 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07002540 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002541 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07002542 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002543 callingUid,
2544 null, // packageName
2545 visibleAccountTypes);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002546 } finally {
2547 restoreCallingIdentity(identityToken);
2548 }
2549 }
2550
Amith Yamasanif29f2362012-04-05 18:29:52 -07002551 /**
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002552 * Returns accounts for all running users.
2553 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07002554 * @hide
2555 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002556 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002557 public AccountAndUser[] getRunningAccounts() {
2558 final int[] runningUserIds;
2559 try {
2560 runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds();
2561 } catch (RemoteException e) {
2562 // Running in system_server; should never happen
2563 throw new RuntimeException(e);
2564 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002565 return getAccounts(runningUserIds);
2566 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07002567
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002568 /** {@hide} */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002569 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002570 public AccountAndUser[] getAllAccounts() {
2571 final List<UserInfo> users = getUserManager().getUsers();
2572 final int[] userIds = new int[users.size()];
2573 for (int i = 0; i < userIds.length; i++) {
2574 userIds[i] = users.get(i).id;
2575 }
2576 return getAccounts(userIds);
2577 }
2578
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002579 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002580 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002581 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07002582 for (int userId : userIds) {
2583 UserAccounts userAccounts = getUserAccounts(userId);
2584 if (userAccounts == null) continue;
2585 synchronized (userAccounts.cacheLock) {
2586 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null,
2587 Binder.getCallingUid(), null);
2588 for (int a = 0; a < accounts.length; a++) {
2589 runningAccounts.add(new AccountAndUser(accounts[a], userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07002590 }
2591 }
2592 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002593
2594 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
2595 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07002596 }
2597
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002598 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002599 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07002600 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
2601 return getAccountsAsUser(type, userId, null, -1, opPackageName);
Amith Yamasani27db4682013-03-30 17:07:47 -07002602 }
2603
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002604 @NonNull
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002605 private Account[] getAccountsAsUser(
2606 String type,
2607 int userId,
2608 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07002609 int packageUid,
2610 String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07002611 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002612 // Only allow the system process to read accounts of other users
2613 if (userId != UserHandle.getCallingUserId()
Amith Yamasanibb49e852013-03-30 19:20:18 -07002614 && callingUid != Process.myUid()
Jim Miller464f5302013-02-27 18:33:25 -08002615 && mContext.checkCallingOrSelfPermission(
2616 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2617 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002618 throw new SecurityException("User " + UserHandle.getCallingUserId()
2619 + " trying to get account for " + userId);
2620 }
2621
Fred Quintana56285a62010-12-02 14:20:51 -08002622 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2623 Log.v(TAG, "getAccounts: accountType " + type
2624 + ", caller's uid " + Binder.getCallingUid()
2625 + ", pid " + Binder.getCallingPid());
2626 }
Amith Yamasani27db4682013-03-30 17:07:47 -07002627 // If the original calling app was using the framework account chooser activity, we'll
2628 // be passed in the original caller's uid here, which is what should be used for filtering.
2629 if (packageUid != -1 && UserHandle.isSameApp(callingUid, Process.myUid())) {
2630 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07002631 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07002632 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002633
Svetoslavf3f02ac2015-09-08 14:36:35 -07002634 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
2635 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002636 if (visibleAccountTypes.isEmpty()
2637 || (type != null && !visibleAccountTypes.contains(type))) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002638 return new Account[0];
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002639 } else if (visibleAccountTypes.contains(type)) {
2640 // Prune the list down to just the requested type.
2641 visibleAccountTypes = new ArrayList<>();
2642 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07002643 } // else aggregate all the visible accounts (it won't matter if the
2644 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002645
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002646 long identityToken = clearCallingIdentity();
2647 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07002648 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002649 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07002650 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002651 callingUid,
2652 callingPackage,
2653 visibleAccountTypes);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002654 } finally {
2655 restoreCallingIdentity(identityToken);
2656 }
2657 }
2658
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002659 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002660 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07002661 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002662 int callingUid,
2663 String callingPackage,
2664 List<String> visibleAccountTypes) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07002665 synchronized (userAccounts.cacheLock) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002666 ArrayList<Account> visibleAccounts = new ArrayList<>();
2667 for (String visibleType : visibleAccountTypes) {
2668 Account[] accountsForType = getAccountsFromCacheLocked(
2669 userAccounts, visibleType, callingUid, callingPackage);
2670 if (accountsForType != null) {
2671 visibleAccounts.addAll(Arrays.asList(accountsForType));
2672 }
2673 }
2674 Account[] result = new Account[visibleAccounts.size()];
2675 for (int i = 0; i < visibleAccounts.size(); i++) {
2676 result[i] = visibleAccounts.get(i);
2677 }
2678 return result;
2679 }
2680 }
2681
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002682 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002683 public void addSharedAccountsFromParentUser(int parentUserId, int userId) {
2684 checkManageUsersPermission("addSharedAccountsFromParentUser");
2685 Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName());
2686 for (Account account : accounts) {
2687 addSharedAccountAsUser(account, userId);
2688 }
2689 }
2690
2691 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08002692 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002693 UserAccounts accounts = getUserAccounts(userId);
2694 SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Amith Yamasani67df64b2012-12-14 12:09:36 -08002695 ContentValues values = new ContentValues();
2696 values.put(ACCOUNTS_NAME, account.name);
2697 values.put(ACCOUNTS_TYPE, account.type);
2698 db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
2699 new String[] {account.name, account.type});
2700 long accountId = db.insert(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
2701 if (accountId < 0) {
2702 Log.w(TAG, "insertAccountIntoDatabase: " + account
2703 + ", skipping the DB insert failed");
2704 return false;
2705 }
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002706 logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_SHARED_ACCOUNTS, accountId, accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002707 return true;
2708 }
2709
2710 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002711 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
2712 userId = handleIncomingUser(userId);
2713 UserAccounts accounts = getUserAccounts(userId);
2714 SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002715 long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002716 final ContentValues values = new ContentValues();
2717 values.put(ACCOUNTS_NAME, newName);
2718 values.put(ACCOUNTS_PREVIOUS_NAME, account.name);
2719 int r = db.update(
2720 TABLE_SHARED_ACCOUNTS,
2721 values,
2722 ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
2723 new String[] { account.name, account.type });
2724 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002725 int callingUid = getCallingUid();
2726 logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_SHARED_ACCOUNTS,
2727 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002728 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002729 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002730 }
2731 return r > 0;
2732 }
2733
2734 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08002735 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002736 return removeSharedAccountAsUser(account, userId, getCallingUid());
2737 }
2738
2739 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08002740 userId = handleIncomingUser(userId);
2741 UserAccounts accounts = getUserAccounts(userId);
2742 SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002743 long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002744 int r = db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
2745 new String[] {account.name, account.type});
2746 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002747 logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
2748 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002749 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002750 }
2751 return r > 0;
2752 }
2753
2754 @Override
2755 public Account[] getSharedAccountsAsUser(int userId) {
2756 userId = handleIncomingUser(userId);
2757 UserAccounts accounts = getUserAccounts(userId);
2758 ArrayList<Account> accountList = new ArrayList<Account>();
2759 Cursor cursor = null;
2760 try {
2761 cursor = accounts.openHelper.getReadableDatabase()
2762 .query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_NAME, ACCOUNTS_TYPE},
2763 null, null, null, null, null);
2764 if (cursor != null && cursor.moveToFirst()) {
2765 int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
2766 int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
2767 do {
2768 accountList.add(new Account(cursor.getString(nameIndex),
2769 cursor.getString(typeIndex)));
2770 } while (cursor.moveToNext());
2771 }
2772 } finally {
2773 if (cursor != null) {
2774 cursor.close();
2775 }
2776 }
2777 Account[] accountArray = new Account[accountList.size()];
2778 accountList.toArray(accountArray);
2779 return accountArray;
2780 }
2781
2782 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002783 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07002784 public Account[] getAccounts(String type, String opPackageName) {
2785 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002786 }
2787
Amith Yamasani27db4682013-03-30 17:07:47 -07002788 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002789 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07002790 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07002791 int callingUid = Binder.getCallingUid();
2792 if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
2793 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
2794 + callingUid + " with uid=" + uid);
2795 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07002796 return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid,
2797 opPackageName);
Amith Yamasani27db4682013-03-30 17:07:47 -07002798 }
2799
Amith Yamasani3b458ad2013-04-18 18:40:07 -07002800 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002801 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07002802 public Account[] getAccountsByTypeForPackage(String type, String packageName,
2803 String opPackageName) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07002804 int packageUid = -1;
2805 try {
2806 packageUid = AppGlobals.getPackageManager().getPackageUid(
2807 packageName, UserHandle.getCallingUserId());
2808 } catch (RemoteException re) {
2809 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
2810 return new Account[0];
2811 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07002812 return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName,
2813 packageUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07002814 }
2815
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002816 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002817 public void getAccountsByFeatures(
2818 IAccountManagerResponse response,
2819 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07002820 String[] features,
2821 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002822 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002823 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2824 Log.v(TAG, "getAccounts: accountType " + type
2825 + ", response " + response
2826 + ", features " + stringArrayToString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002827 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002828 + ", pid " + Binder.getCallingPid());
2829 }
Fred Quintana382601f2010-03-25 12:25:10 -07002830 if (response == null) throw new IllegalArgumentException("response is null");
2831 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002832 int userId = UserHandle.getCallingUserId();
2833
Svetoslavf3f02ac2015-09-08 14:36:35 -07002834 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
2835 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002836 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002837 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002838 // Need to return just the accounts that are from matching signatures.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002839 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);
2840 try {
2841 response.onResult(result);
2842 } catch (RemoteException e) {
2843 Log.e(TAG, "Cannot respond to caller do to exception." , e);
2844 }
2845 return;
2846 }
Fred Quintana33269202009-04-20 16:05:10 -07002847 long identityToken = clearCallingIdentity();
2848 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002849 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002850 if (features == null || features.length == 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002851 Account[] accounts;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002852 synchronized (userAccounts.cacheLock) {
Amith Yamasani27db4682013-03-30 17:07:47 -07002853 accounts = getAccountsFromCacheLocked(userAccounts, type, callingUid, null);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002854 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002855 Bundle result = new Bundle();
2856 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
2857 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002858 return;
2859 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002860 new GetAccountsByTypeAndFeatureSession(
2861 userAccounts,
2862 response,
2863 type,
2864 features,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002865 callingUid).bind();
Fred Quintana33269202009-04-20 16:05:10 -07002866 } finally {
2867 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002868 }
2869 }
2870
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002871 private long getAccountIdFromSharedTable(SQLiteDatabase db, Account account) {
2872 Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_ID},
2873 "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
2874 try {
2875 if (cursor.moveToNext()) {
2876 return cursor.getLong(0);
2877 }
2878 return -1;
2879 } finally {
2880 cursor.close();
2881 }
2882 }
2883
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002884 private long getAccountIdLocked(SQLiteDatabase db, Account account) {
Fred Quintana60307342009-03-24 22:48:12 -07002885 Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002886 "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
Fred Quintana60307342009-03-24 22:48:12 -07002887 try {
2888 if (cursor.moveToNext()) {
2889 return cursor.getLong(0);
2890 }
2891 return -1;
2892 } finally {
2893 cursor.close();
2894 }
2895 }
2896
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002897 private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
Fred Quintana60307342009-03-24 22:48:12 -07002898 Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
2899 EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
2900 new String[]{key}, null, null, null);
2901 try {
2902 if (cursor.moveToNext()) {
2903 return cursor.getLong(0);
2904 }
2905 return -1;
2906 } finally {
2907 cursor.close();
2908 }
2909 }
2910
Fred Quintanaa698f422009-04-08 19:14:54 -07002911 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07002912 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07002913 IAccountManagerResponse mResponse;
2914 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07002915 final boolean mExpectActivityLaunch;
2916 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002917 final String mAccountName;
2918 // Indicates if we need to add auth details(like last credential time)
2919 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07002920 // If set, we need to update the last authenticated time. This is
2921 // currently
2922 // used on
2923 // successful confirming credentials.
2924 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07002925
Fred Quintana33269202009-04-20 16:05:10 -07002926 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07002927 private int mNumRequestContinued = 0;
2928 private int mNumErrors = 0;
2929
Fred Quintana60307342009-03-24 22:48:12 -07002930 IAccountAuthenticator mAuthenticator = null;
2931
Fred Quintana8570f742010-02-18 10:32:54 -08002932 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002933 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08002934
Amith Yamasani04e0d262012-02-14 11:50:53 -08002935 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002936 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
2937 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07002938 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
2939 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
2940 }
2941
2942 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
2943 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
2944 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07002945 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08002946 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07002947 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002948 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08002949 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07002950 mResponse = response;
2951 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07002952 mExpectActivityLaunch = expectActivityLaunch;
2953 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002954 mAccountName = accountName;
2955 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07002956 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002957
Fred Quintanaa698f422009-04-08 19:14:54 -07002958 synchronized (mSessions) {
2959 mSessions.put(toString(), this);
2960 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002961 if (response != null) {
2962 try {
2963 response.asBinder().linkToDeath(this, 0 /* flags */);
2964 } catch (RemoteException e) {
2965 mResponse = null;
2966 binderDied();
2967 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002968 }
Fred Quintana60307342009-03-24 22:48:12 -07002969 }
2970
Fred Quintanaa698f422009-04-08 19:14:54 -07002971 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07002972 if (mResponse == null) {
2973 // this session has already been closed
2974 return null;
2975 }
Fred Quintana60307342009-03-24 22:48:12 -07002976 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07002977 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07002978 return response;
2979 }
2980
Fred Quintanaa698f422009-04-08 19:14:54 -07002981 private void close() {
2982 synchronized (mSessions) {
2983 if (mSessions.remove(toString()) == null) {
2984 // the session was already closed, so bail out now
2985 return;
2986 }
2987 }
2988 if (mResponse != null) {
2989 // stop listening for response deaths
2990 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
2991
2992 // clear this so that we don't accidentally send any further results
2993 mResponse = null;
2994 }
2995 cancelTimeout();
2996 unbind();
2997 }
2998
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002999 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003000 public void binderDied() {
3001 mResponse = null;
3002 close();
3003 }
3004
3005 protected String toDebugString() {
3006 return toDebugString(SystemClock.elapsedRealtime());
3007 }
3008
3009 protected String toDebugString(long now) {
3010 return "Session: expectLaunch " + mExpectActivityLaunch
3011 + ", connected " + (mAuthenticator != null)
3012 + ", stats (" + mNumResults + "/" + mNumRequestContinued
3013 + "/" + mNumErrors + ")"
3014 + ", lifetime " + ((now - mCreationTime) / 1000.0);
3015 }
3016
Fred Quintana60307342009-03-24 22:48:12 -07003017 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07003018 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3019 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
3020 }
Fred Quintanab839afc2009-10-14 15:57:28 -07003021 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07003022 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003023 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07003024 }
3025 }
3026
3027 private void unbind() {
3028 if (mAuthenticator != null) {
3029 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07003030 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07003031 }
3032 }
3033
Fred Quintana60307342009-03-24 22:48:12 -07003034 public void cancelTimeout() {
3035 mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
3036 }
3037
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003038 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07003039 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07003040 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07003041 try {
3042 run();
3043 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003044 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07003045 "remote exception");
3046 }
Fred Quintana60307342009-03-24 22:48:12 -07003047 }
3048
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003049 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07003050 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07003051 mAuthenticator = null;
3052 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07003053 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07003054 try {
3055 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
3056 "disconnected");
3057 } catch (RemoteException e) {
3058 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3059 Log.v(TAG, "Session.onServiceDisconnected: "
3060 + "caught RemoteException while responding", e);
3061 }
3062 }
Fred Quintana60307342009-03-24 22:48:12 -07003063 }
3064 }
3065
Fred Quintanab839afc2009-10-14 15:57:28 -07003066 public abstract void run() throws RemoteException;
3067
Fred Quintana60307342009-03-24 22:48:12 -07003068 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07003069 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07003070 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07003071 try {
3072 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
3073 "timeout");
3074 } catch (RemoteException e) {
3075 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3076 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
3077 e);
3078 }
3079 }
Fred Quintana60307342009-03-24 22:48:12 -07003080 }
3081 }
3082
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003083 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003084 public void onResult(Bundle result) {
3085 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003086 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003087 if (result != null) {
3088 boolean isSuccessfulConfirmCreds = result.getBoolean(
3089 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003090 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003091 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
3092 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07003093 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003094 // mUpdateLastAuthenticatedTime is true and the confirmRequest
3095 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07003096 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003097 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003098 if (needUpdate || mAuthDetailsRequired) {
3099 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
3100 if (needUpdate && accountPresent) {
3101 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
3102 }
3103 if (mAuthDetailsRequired) {
3104 long lastAuthenticatedTime = -1;
3105 if (accountPresent) {
3106 lastAuthenticatedTime = DatabaseUtils.longForQuery(
3107 mAccounts.openHelper.getReadableDatabase(),
3108 "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
3109 + " from " +
3110 TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
3111 + ACCOUNTS_TYPE + "=?",
3112 new String[] {
3113 mAccountName, mAccountType
3114 });
3115 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07003116 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003117 lastAuthenticatedTime);
3118 }
3119 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003120 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003121 if (result != null
3122 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
3123 /*
3124 * The Authenticator API allows third party authenticators to
3125 * supply arbitrary intents to other apps that they can run,
3126 * this can be very bad when those apps are in the system like
3127 * the System Settings.
3128 */
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003129 int authenticatorUid = Binder.getCallingUid();
Carlos Valdivia416747a2013-10-14 17:22:42 -07003130 long bid = Binder.clearCallingIdentity();
3131 try {
3132 PackageManager pm = mContext.getPackageManager();
3133 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
3134 int targetUid = resolveInfo.activityInfo.applicationInfo.uid;
3135 if (PackageManager.SIGNATURE_MATCH !=
3136 pm.checkSignatures(authenticatorUid, targetUid)) {
3137 throw new SecurityException(
3138 "Activity to be started with KEY_INTENT must " +
3139 "share Authenticator's signatures");
3140 }
3141 } finally {
3142 Binder.restoreCallingIdentity(bid);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003143 }
3144 }
3145 if (result != null
3146 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003147 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
3148 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003149 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
3150 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003151 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
3152 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003153 }
Fred Quintana60307342009-03-24 22:48:12 -07003154 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003155 IAccountManagerResponse response;
3156 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003157 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07003158 response = mResponse;
3159 } else {
3160 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07003161 }
Fred Quintana60307342009-03-24 22:48:12 -07003162 if (response != null) {
3163 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07003164 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08003165 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3166 Log.v(TAG, getClass().getSimpleName()
3167 + " calling onError() on response " + response);
3168 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003169 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07003170 "null bundle returned");
3171 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08003172 if (mStripAuthTokenFromResult) {
3173 result.remove(AccountManager.KEY_AUTHTOKEN);
3174 }
Fred Quintana56285a62010-12-02 14:20:51 -08003175 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3176 Log.v(TAG, getClass().getSimpleName()
3177 + " calling onResult() on response " + response);
3178 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003179 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
3180 (intent == null)) {
3181 // All AccountManager error codes are greater than 0
3182 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
3183 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3184 } else {
3185 response.onResult(result);
3186 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003187 }
Fred Quintana60307342009-03-24 22:48:12 -07003188 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07003189 // if the caller is dead then there is no one to care about remote exceptions
3190 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3191 Log.v(TAG, "failure while notifying response", e);
3192 }
Fred Quintana60307342009-03-24 22:48:12 -07003193 }
3194 }
3195 }
Fred Quintana60307342009-03-24 22:48:12 -07003196
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003197 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003198 public void onRequestContinued() {
3199 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07003200 }
3201
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003202 @Override
Fred Quintana60307342009-03-24 22:48:12 -07003203 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07003204 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07003205 IAccountManagerResponse response = getResponseAndClose();
3206 if (response != null) {
3207 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08003208 Log.v(TAG, getClass().getSimpleName()
3209 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07003210 }
3211 try {
3212 response.onError(errorCode, errorMessage);
3213 } catch (RemoteException e) {
3214 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3215 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
3216 }
3217 }
3218 } else {
3219 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3220 Log.v(TAG, "Session.onError: already closed");
3221 }
Fred Quintana60307342009-03-24 22:48:12 -07003222 }
3223 }
Fred Quintanab839afc2009-10-14 15:57:28 -07003224
3225 /**
3226 * find the component name for the authenticator and initiate a bind
3227 * if no authenticator or the bind fails then return false, otherwise return true
3228 */
3229 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003230 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
3231 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
3232 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07003233 if (authenticatorInfo == null) {
3234 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3235 Log.v(TAG, "there is no authenticator for " + authenticatorType
3236 + ", bailing out");
3237 }
3238 return false;
3239 }
3240
3241 Intent intent = new Intent();
3242 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
3243 intent.setComponent(authenticatorInfo.componentName);
3244 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3245 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
3246 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08003247 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
3248 new UserHandle(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07003249 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3250 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
3251 }
3252 return false;
3253 }
3254
3255
3256 return true;
3257 }
Fred Quintana60307342009-03-24 22:48:12 -07003258 }
3259
3260 private class MessageHandler extends Handler {
3261 MessageHandler(Looper looper) {
3262 super(looper);
3263 }
Costin Manolache3348f142009-09-29 18:58:36 -07003264
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003265 @Override
Fred Quintana60307342009-03-24 22:48:12 -07003266 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07003267 switch (msg.what) {
3268 case MESSAGE_TIMED_OUT:
3269 Session session = (Session)msg.obj;
3270 session.onTimedOut();
3271 break;
3272
Amith Yamasani5be347b2013-03-31 17:44:31 -07003273 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00003274 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07003275 break;
3276
Fred Quintana60307342009-03-24 22:48:12 -07003277 default:
3278 throw new IllegalStateException("unhandled message: " + msg.what);
3279 }
3280 }
3281 }
3282
Amith Yamasani04e0d262012-02-14 11:50:53 -08003283 private static String getDatabaseName(int userId) {
3284 File systemDir = Environment.getSystemSecureDirectory();
Amith Yamasani61f57372012-08-31 12:12:28 -07003285 File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003286 if (userId == 0) {
Amith Yamasania23bb382012-04-11 15:32:07 -07003287 // Migrate old file, if it exists, to the new location.
3288 // Make sure the new file doesn't already exist. A dummy file could have been
3289 // accidentally created in the old location, causing the new one to become corrupted
3290 // as well.
Amith Yamasani04e0d262012-02-14 11:50:53 -08003291 File oldFile = new File(systemDir, DATABASE_NAME);
Amith Yamasania23bb382012-04-11 15:32:07 -07003292 if (oldFile.exists() && !databaseFile.exists()) {
Marc Blankc6b0f992012-03-18 19:16:41 -07003293 // Check for use directory; create if it doesn't exist, else renameTo will fail
Amith Yamasani61f57372012-08-31 12:12:28 -07003294 File userDir = Environment.getUserSystemDirectory(userId);
Marc Blankc6b0f992012-03-18 19:16:41 -07003295 if (!userDir.exists()) {
3296 if (!userDir.mkdirs()) {
3297 throw new IllegalStateException("User dir cannot be created: " + userDir);
3298 }
3299 }
3300 if (!oldFile.renameTo(databaseFile)) {
3301 throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
3302 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003303 }
Oscar Montemayora8529f62009-11-18 10:14:20 -08003304 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003305 return databaseFile.getPath();
Oscar Montemayora8529f62009-11-18 10:14:20 -08003306 }
3307
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003308 private static class DebugDbHelper{
3309 private DebugDbHelper() {
3310 }
3311
3312 private static String TABLE_DEBUG = "debug_table";
3313
3314 // Columns for the table
3315 private static String ACTION_TYPE = "action_type";
3316 private static String TIMESTAMP = "time";
3317 private static String CALLER_UID = "caller_uid";
3318 private static String TABLE_NAME = "table_name";
3319 private static String KEY = "primary_key";
3320
3321 // These actions correspond to the occurrence of real actions. Since
3322 // these are called by the authenticators, the uid associated will be
3323 // of the authenticator.
3324 private static String ACTION_SET_PASSWORD = "action_set_password";
3325 private static String ACTION_CLEAR_PASSWORD = "action_clear_password";
3326 private static String ACTION_ACCOUNT_ADD = "action_account_add";
3327 private static String ACTION_ACCOUNT_REMOVE = "action_account_remove";
3328 private static String ACTION_AUTHENTICATOR_REMOVE = "action_authenticator_remove";
3329 private static String ACTION_ACCOUNT_RENAME = "action_account_rename";
3330
3331 // These actions don't necessarily correspond to any action on
3332 // accountDb taking place. As an example, there might be a request for
3333 // addingAccount, which might not lead to addition of account on grounds
3334 // of bad authentication. We will still be logging it to keep track of
3335 // who called.
3336 private static String ACTION_CALLED_ACCOUNT_ADD = "action_called_account_add";
3337 private static String ACTION_CALLED_ACCOUNT_REMOVE = "action_called_account_remove";
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003338
3339 private static SimpleDateFormat dateFromat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
3340
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003341 private static void createDebugTable(SQLiteDatabase db) {
3342 db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
3343 + ACCOUNTS_ID + " INTEGER,"
3344 + ACTION_TYPE + " TEXT NOT NULL, "
3345 + TIMESTAMP + " DATETIME,"
3346 + CALLER_UID + " INTEGER NOT NULL,"
3347 + TABLE_NAME + " TEXT NOT NULL,"
3348 + KEY + " INTEGER PRIMARY KEY)");
3349 db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " (" + TIMESTAMP + ")");
3350 }
3351 }
3352
3353 private void logRecord(UserAccounts accounts, String action, String tableName) {
3354 SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
3355 logRecord(db, action, tableName, -1, accounts);
3356 }
3357
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003358 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
3359 SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
3360 logRecord(db, action, tableName, -1, accounts, uid);
3361 }
3362
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003363 /*
3364 * This function receives an opened writable database.
3365 */
3366 private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
3367 UserAccounts userAccount) {
3368 logRecord(db, action, tableName, accountId, userAccount, getCallingUid());
3369 }
3370
3371 /*
3372 * This function receives an opened writable database.
3373 */
3374 private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
3375 UserAccounts userAccount, int callingUid) {
3376 SQLiteStatement logStatement = userAccount.statementForLogging;
3377 logStatement.bindLong(1, accountId);
3378 logStatement.bindString(2, action);
3379 logStatement.bindString(3, DebugDbHelper.dateFromat.format(new Date()));
3380 logStatement.bindLong(4, callingUid);
3381 logStatement.bindString(5, tableName);
3382 logStatement.bindLong(6, userAccount.debugDbInsertionPoint);
3383 logStatement.execute();
3384 logStatement.clearBindings();
3385 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
3386 % MAX_DEBUG_DB_SIZE;
3387 }
3388
3389 /*
3390 * This should only be called once to compile the sql statement for logging
3391 * and to find the insertion point.
3392 */
3393 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(SQLiteDatabase db,
3394 UserAccounts userAccount) {
3395 // Initialize the count if not done earlier.
3396 int size = (int) getDebugTableRowCount(db);
3397 if (size >= MAX_DEBUG_DB_SIZE) {
3398 // Table is full, and we need to find the point where to insert.
3399 userAccount.debugDbInsertionPoint = (int) getDebugTableInsertionPoint(db);
3400 } else {
3401 userAccount.debugDbInsertionPoint = size;
3402 }
3403 compileSqlStatementForLogging(db, userAccount);
3404 }
3405
3406 private void compileSqlStatementForLogging(SQLiteDatabase db, UserAccounts userAccount) {
3407 String sql = "INSERT OR REPLACE INTO " + DebugDbHelper.TABLE_DEBUG
3408 + " VALUES (?,?,?,?,?,?)";
3409 userAccount.statementForLogging = db.compileStatement(sql);
3410 }
3411
3412 private long getDebugTableRowCount(SQLiteDatabase db) {
3413 String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + DebugDbHelper.TABLE_DEBUG;
3414 return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
3415 }
3416
3417 /*
3418 * Finds the row key where the next insertion should take place. This should
3419 * be invoked only if the table has reached its full capacity.
3420 */
3421 private long getDebugTableInsertionPoint(SQLiteDatabase db) {
3422 // This query finds the smallest timestamp value (and if 2 records have
3423 // same timestamp, the choose the lower id).
3424 String queryCountDebugDbRows = new StringBuilder()
3425 .append("SELECT ").append(DebugDbHelper.KEY)
3426 .append(" FROM ").append(DebugDbHelper.TABLE_DEBUG)
3427 .append(" ORDER BY ")
3428 .append(DebugDbHelper.TIMESTAMP).append(",").append(DebugDbHelper.KEY)
3429 .append(" LIMIT 1")
3430 .toString();
3431 return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
3432 }
3433
Amith Yamasani04e0d262012-02-14 11:50:53 -08003434 static class DatabaseHelper extends SQLiteOpenHelper {
Oscar Montemayora8529f62009-11-18 10:14:20 -08003435
Amith Yamasani04e0d262012-02-14 11:50:53 -08003436 public DatabaseHelper(Context context, int userId) {
3437 super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
Fred Quintana60307342009-03-24 22:48:12 -07003438 }
3439
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003440 /**
3441 * This call needs to be made while the mCacheLock is held. The way to
3442 * ensure this is to get the lock any time a method is called ont the DatabaseHelper
3443 * @param db The database.
3444 */
Fred Quintana60307342009-03-24 22:48:12 -07003445 @Override
3446 public void onCreate(SQLiteDatabase db) {
3447 db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
3448 + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
3449 + ACCOUNTS_NAME + " TEXT NOT NULL, "
3450 + ACCOUNTS_TYPE + " TEXT NOT NULL, "
3451 + ACCOUNTS_PASSWORD + " TEXT, "
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07003452 + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003453 + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
Fred Quintana60307342009-03-24 22:48:12 -07003454 + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
3455
3456 db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
3457 + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
3458 + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
3459 + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
3460 + AUTHTOKENS_AUTHTOKEN + " TEXT, "
3461 + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
3462
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003463 createGrantsTable(db);
3464
Fred Quintana60307342009-03-24 22:48:12 -07003465 db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
3466 + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
3467 + EXTRAS_ACCOUNTS_ID + " INTEGER, "
3468 + EXTRAS_KEY + " TEXT NOT NULL, "
3469 + EXTRAS_VALUE + " TEXT, "
3470 + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
3471
3472 db.execSQL("CREATE TABLE " + TABLE_META + " ( "
3473 + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
3474 + META_VALUE + " TEXT)");
Fred Quintanaa698f422009-04-08 19:14:54 -07003475
Amith Yamasani67df64b2012-12-14 12:09:36 -08003476 createSharedAccountsTable(db);
3477
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003478 createAccountsDeletionTrigger(db);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003479
3480 DebugDbHelper.createDebugTable(db);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003481 }
3482
Amith Yamasani67df64b2012-12-14 12:09:36 -08003483 private void createSharedAccountsTable(SQLiteDatabase db) {
3484 db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
3485 + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
3486 + ACCOUNTS_NAME + " TEXT NOT NULL, "
3487 + ACCOUNTS_TYPE + " TEXT NOT NULL, "
3488 + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
3489 }
3490
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003491 private void addLastSuccessfullAuthenticatedTimeColumn(SQLiteDatabase db) {
3492 db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN "
3493 + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " DEFAULT 0");
3494 }
3495
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07003496 private void addOldAccountNameColumn(SQLiteDatabase db) {
3497 db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN " + ACCOUNTS_PREVIOUS_NAME);
3498 }
3499
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003500 private void addDebugTable(SQLiteDatabase db) {
3501 DebugDbHelper.createDebugTable(db);
3502 }
3503
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003504 private void createAccountsDeletionTrigger(SQLiteDatabase db) {
Fred Quintanaa698f422009-04-08 19:14:54 -07003505 db.execSQL(""
3506 + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
3507 + " BEGIN"
3508 + " DELETE FROM " + TABLE_AUTHTOKENS
3509 + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
3510 + " DELETE FROM " + TABLE_EXTRAS
3511 + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003512 + " DELETE FROM " + TABLE_GRANTS
3513 + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
Fred Quintanaa698f422009-04-08 19:14:54 -07003514 + " END");
Fred Quintana60307342009-03-24 22:48:12 -07003515 }
3516
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003517 private void createGrantsTable(SQLiteDatabase db) {
3518 db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
3519 + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
3520 + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
3521 + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
3522 + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
3523 + "," + GRANTS_GRANTEE_UID + "))");
3524 }
3525
Fred Quintana60307342009-03-24 22:48:12 -07003526 @Override
3527 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Fred Quintanaa698f422009-04-08 19:14:54 -07003528 Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
Fred Quintana60307342009-03-24 22:48:12 -07003529
Fred Quintanaa698f422009-04-08 19:14:54 -07003530 if (oldVersion == 1) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003531 // no longer need to do anything since the work is done
3532 // when upgrading from version 2
3533 oldVersion++;
3534 }
3535
3536 if (oldVersion == 2) {
3537 createGrantsTable(db);
3538 db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
3539 createAccountsDeletionTrigger(db);
Fred Quintanaa698f422009-04-08 19:14:54 -07003540 oldVersion++;
3541 }
Costin Manolache3348f142009-09-29 18:58:36 -07003542
3543 if (oldVersion == 3) {
3544 db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
3545 " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
3546 oldVersion++;
3547 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08003548
3549 if (oldVersion == 4) {
3550 createSharedAccountsTable(db);
3551 oldVersion++;
3552 }
3553
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07003554 if (oldVersion == 5) {
3555 addOldAccountNameColumn(db);
3556 oldVersion++;
3557 }
3558
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003559 if (oldVersion == 6) {
3560 addLastSuccessfullAuthenticatedTimeColumn(db);
3561 oldVersion++;
3562 }
3563
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003564 if (oldVersion == 7) {
3565 addDebugTable(db);
3566 oldVersion++;
3567 }
3568
Amith Yamasani67df64b2012-12-14 12:09:36 -08003569 if (oldVersion != newVersion) {
3570 Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
3571 }
Fred Quintana60307342009-03-24 22:48:12 -07003572 }
3573
3574 @Override
3575 public void onOpen(SQLiteDatabase db) {
3576 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
3577 }
3578 }
3579
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003580 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07003581 return asBinder();
3582 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003583
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003584 /**
3585 * Searches array of arguments for the specified string
3586 * @param args array of argument strings
3587 * @param value value to search for
3588 * @return true if the value is contained in the array
3589 */
3590 private static boolean scanArgs(String[] args, String value) {
3591 if (args != null) {
3592 for (String arg : args) {
3593 if (value.equals(arg)) {
3594 return true;
3595 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003596 }
3597 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003598 return false;
3599 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003600
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003601 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003602 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Kenny Root3abd75b2011-09-29 11:00:41 -07003603 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
3604 != PackageManager.PERMISSION_GRANTED) {
3605 fout.println("Permission Denial: can't dump AccountsManager from from pid="
3606 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
3607 + " without permission " + android.Manifest.permission.DUMP);
3608 return;
3609 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003610 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003611 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07003612
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003613 final List<UserInfo> users = getUserManager().getUsers();
3614 for (UserInfo user : users) {
3615 ipw.println("User " + user + ":");
3616 ipw.increaseIndent();
3617 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
3618 ipw.println();
3619 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08003620 }
3621 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003622
Amith Yamasani04e0d262012-02-14 11:50:53 -08003623 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
3624 String[] args, boolean isCheckinRequest) {
3625 synchronized (userAccounts.cacheLock) {
3626 final SQLiteDatabase db = userAccounts.openHelper.getReadableDatabase();
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003627
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003628 if (isCheckinRequest) {
3629 // This is a checkin request. *Only* upload the account types and the count of each.
3630 Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
3631 null, null, ACCOUNTS_TYPE, null, null);
3632 try {
3633 while (cursor.moveToNext()) {
3634 // print type,count
3635 fout.println(cursor.getString(0) + "," + cursor.getString(1));
3636 }
3637 } finally {
3638 if (cursor != null) {
3639 cursor.close();
3640 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003641 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003642 } else {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003643 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Amith Yamasani27db4682013-03-30 17:07:47 -07003644 Process.myUid(), null);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003645 fout.println("Accounts: " + accounts.length);
3646 for (Account account : accounts) {
3647 fout.println(" " + account);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003648 }
Fred Quintana307da1a2010-01-21 14:24:20 -08003649
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07003650 // Add debug information.
3651 fout.println();
3652 Cursor cursor = db.query(DebugDbHelper.TABLE_DEBUG, null,
3653 null, null, null, null, DebugDbHelper.TIMESTAMP);
3654 fout.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
3655 fout.println("Accounts History");
3656 try {
3657 while (cursor.moveToNext()) {
3658 // print type,count
3659 fout.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
3660 cursor.getString(2) + "," + cursor.getString(3) + ","
3661 + cursor.getString(4) + "," + cursor.getString(5));
3662 }
3663 } finally {
3664 cursor.close();
3665 }
3666
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003667 fout.println();
3668 synchronized (mSessions) {
3669 final long now = SystemClock.elapsedRealtime();
3670 fout.println("Active Sessions: " + mSessions.size());
3671 for (Session session : mSessions.values()) {
3672 fout.println(" " + session.toDebugString(now));
3673 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003674 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003675
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003676 fout.println();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003677 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003678 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07003679 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003680 }
3681
Amith Yamasani04e0d262012-02-14 11:50:53 -08003682 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Dianne Hackborn41203752012-08-31 14:05:51 -07003683 Intent intent, int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003684 long identityToken = clearCallingIdentity();
3685 try {
3686 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3687 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
3688 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003689
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003690 if (intent.getComponent() != null &&
3691 GrantCredentialsPermissionActivity.class.getName().equals(
3692 intent.getComponent().getClassName())) {
Dianne Hackborn41203752012-08-31 14:05:51 -07003693 createNoCredentialsPermissionNotification(account, intent, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003694 } else {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003695 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07003696 intent.addCategory(String.valueOf(notificationId));
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003697 UserHandle user = new UserHandle(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003698 Context contextForUser = getContextForUser(user);
Fred Quintana33f889a2009-09-14 17:31:26 -07003699 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003700 contextForUser.getText(R.string.notification_title).toString();
Chris Wren1ce4b6d2015-06-11 10:19:43 -04003701 Notification n = new Notification.Builder(contextForUser)
3702 .setWhen(0)
3703 .setSmallIcon(android.R.drawable.stat_sys_warning)
3704 .setColor(contextForUser.getColor(
3705 com.android.internal.R.color.system_notification_accent_color))
3706 .setContentTitle(String.format(notificationTitleFormat, account.name))
3707 .setContentText(message)
3708 .setContentIntent(PendingIntent.getActivityAsUser(
3709 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
3710 null, user))
3711 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003712 installNotification(notificationId, n, user);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003713 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003714 } finally {
3715 restoreCallingIdentity(identityToken);
3716 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003717 }
3718
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003719 protected void installNotification(final int notificationId, final Notification n,
3720 UserHandle user) {
Fred Quintana56285a62010-12-02 14:20:51 -08003721 ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003722 .notifyAsUser(null, notificationId, n, user);
Fred Quintana56285a62010-12-02 14:20:51 -08003723 }
3724
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003725 protected void cancelNotification(int id, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003726 long identityToken = clearCallingIdentity();
3727 try {
3728 ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003729 .cancelAsUser(null, id, user);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003730 } finally {
3731 restoreCallingIdentity(identityToken);
3732 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003733 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003734
Svetoslavf3f02ac2015-09-08 14:36:35 -07003735 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
Fred Quintanab38eb142010-02-24 13:40:54 -08003736 for (String perm : permissions) {
3737 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
3738 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003739 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
Fred Quintanab38eb142010-02-24 13:40:54 -08003740 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07003741 final int opCode = AppOpsManager.permissionToOpCode(perm);
3742 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
3743 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
3744 return true;
3745 }
Fred Quintanab38eb142010-02-24 13:40:54 -08003746 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003747 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003748 return false;
3749 }
3750
Amith Yamasani67df64b2012-12-14 12:09:36 -08003751 private int handleIncomingUser(int userId) {
3752 try {
3753 return ActivityManagerNative.getDefault().handleIncomingUser(
3754 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
3755 } catch (RemoteException re) {
3756 // Shouldn't happen, local.
3757 }
3758 return userId;
3759 }
3760
Christopher Tateccbf84f2013-05-08 15:25:41 -07003761 private boolean isPrivileged(int callingUid) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003762 final int callingUserId = UserHandle.getUserId(callingUid);
3763
3764 final PackageManager userPackageManager;
3765 try {
3766 userPackageManager = mContext.createPackageContextAsUser(
3767 "android", 0, new UserHandle(callingUserId)).getPackageManager();
3768 } catch (NameNotFoundException e) {
3769 return false;
3770 }
3771
3772 String[] packages = userPackageManager.getPackagesForUid(callingUid);
Fred Quintana7be59642009-08-24 18:29:25 -07003773 for (String name : packages) {
3774 try {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003775 PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08003776 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08003777 && (packageInfo.applicationInfo.privateFlags
3778 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07003779 return true;
3780 }
3781 } catch (PackageManager.NameNotFoundException e) {
3782 return false;
3783 }
3784 }
3785 return false;
3786 }
3787
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003788 private boolean permissionIsGranted(
3789 Account account, String authTokenType, int callerUid, int userId) {
Christopher Tateccbf84f2013-05-08 15:25:41 -07003790 final boolean isPrivileged = isPrivileged(callerUid);
Fred Quintana31957f12009-10-21 13:43:10 -07003791 final boolean fromAuthenticator = account != null
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003792 && isAccountManagedByCaller(account.type, callerUid, userId);
Fred Quintana31957f12009-10-21 13:43:10 -07003793 final boolean hasExplicitGrants = account != null
Amith Yamasani04e0d262012-02-14 11:50:53 -08003794 && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003795 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3796 Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
Fred Quintana56285a62010-12-02 14:20:51 -08003797 + callerUid + ", " + account
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003798 + ": is authenticator? " + fromAuthenticator
3799 + ", has explicit permission? " + hasExplicitGrants);
3800 }
Christopher Tateccbf84f2013-05-08 15:25:41 -07003801 return fromAuthenticator || hasExplicitGrants || isPrivileged;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003802 }
3803
Svetoslavf3f02ac2015-09-08 14:36:35 -07003804 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
3805 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003806 if (accountType == null) {
3807 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003808 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07003809 return getTypesVisibleToCaller(callingUid, userId,
3810 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003811 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003812 }
3813
3814 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
3815 if (accountType == null) {
3816 return false;
3817 } else {
3818 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
3819 }
3820 }
3821
Svetoslavf3f02ac2015-09-08 14:36:35 -07003822 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
3823 String opPackageName) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003824 boolean isPermitted =
Svetoslavf3f02ac2015-09-08 14:36:35 -07003825 isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003826 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
3827 Log.i(TAG, String.format("getTypesVisibleToCaller: isPermitted? %s", isPermitted));
3828 return getTypesForCaller(callingUid, userId, isPermitted);
3829 }
3830
3831 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
3832 return getTypesForCaller(callingUid, userId, false);
3833 }
3834
3835 private List<String> getTypesForCaller(
3836 int callingUid, int userId, boolean isOtherwisePermitted) {
3837 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07003838 long identityToken = Binder.clearCallingIdentity();
3839 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
3840 try {
3841 serviceInfos = mAuthenticatorCache.getAllServices(userId);
3842 } finally {
3843 Binder.restoreCallingIdentity(identityToken);
3844 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003845 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07003846 serviceInfos) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003847 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
3848 if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) {
3849 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003850 }
3851 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003852 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003853 }
3854
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003855 private boolean isAccountPresentForCaller(String accountName, String accountType) {
3856 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
3857 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
3858 if (account.name.equals(accountName)) {
3859 return true;
3860 }
3861 }
3862 }
3863 return false;
3864 }
3865
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003866 private static void checkManageUsersPermission(String message) {
3867 if (ActivityManager.checkComponentPermission(
3868 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
3869 != PackageManager.PERMISSION_GRANTED) {
3870 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
3871 }
3872 }
3873
Amith Yamasani04e0d262012-02-14 11:50:53 -08003874 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
3875 int callerUid) {
Amith Yamasani27db4682013-03-30 17:07:47 -07003876 if (callerUid == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003877 return true;
3878 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003879 UserAccounts accounts = getUserAccountsForCaller();
3880 synchronized (accounts.cacheLock) {
3881 final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
3882 String[] args = { String.valueOf(callerUid), authTokenType,
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003883 account.name, account.type};
3884 final boolean permissionGranted =
3885 DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
3886 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
3887 // TODO: Skip this check when running automated tests. Replace this
3888 // with a more general solution.
3889 Log.d(TAG, "no credentials permission for usage of " + account + ", "
Amith Yamasani04e0d262012-02-14 11:50:53 -08003890 + authTokenType + " by uid " + callerUid
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003891 + " but ignoring since device is in test harness.");
3892 return true;
3893 }
3894 return permissionGranted;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003895 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003896 }
3897
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003898 private boolean isSystemUid(int callingUid) {
3899 String[] packages = null;
3900 long ident = Binder.clearCallingIdentity();
3901 try {
3902 packages = mPackageManager.getPackagesForUid(callingUid);
3903 } finally {
3904 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07003905 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003906 if (packages != null) {
3907 for (String name : packages) {
3908 try {
3909 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
3910 if (packageInfo != null
3911 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
3912 != 0) {
3913 return true;
3914 }
3915 } catch (PackageManager.NameNotFoundException e) {
3916 Log.w(TAG, String.format("Could not find package [%s]", name), e);
3917 }
3918 }
3919 } else {
3920 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07003921 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003922 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00003923 }
3924
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003925 /** Succeeds if any of the specified permissions are granted. */
3926 private void checkReadAccountsPermitted(
3927 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003928 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07003929 int userId,
3930 String opPackageName) {
3931 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003932 String msg = String.format(
3933 "caller uid %s cannot access %s accounts",
3934 callingUid,
3935 accountType);
3936 Log.w(TAG, " " + msg);
3937 throw new SecurityException(msg);
3938 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003939 }
3940
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003941 private boolean canUserModifyAccounts(int userId) {
3942 if (getUserManager().getUserRestrictions(new UserHandle(userId))
3943 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
3944 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08003945 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003946 return true;
3947 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01003948
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003949 private boolean canUserModifyAccountsForType(int userId, String accountType) {
Sander Alewijnseda1350f2014-05-08 16:59:42 +01003950 DevicePolicyManager dpm = (DevicePolicyManager) mContext
3951 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003952 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02003953 if (typesArray == null) {
3954 return true;
3955 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01003956 for (String forbiddenType : typesArray) {
3957 if (forbiddenType.equals(accountType)) {
3958 return false;
3959 }
3960 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08003961 return true;
3962 }
3963
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003964 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07003965 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
3966 throws RemoteException {
3967 final int callingUid = getCallingUid();
3968
Amith Yamasani27db4682013-03-30 17:07:47 -07003969 if (callingUid != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07003970 throw new SecurityException();
3971 }
3972
3973 if (value) {
3974 grantAppPermission(account, authTokenType, uid);
3975 } else {
3976 revokeAppPermission(account, authTokenType, uid);
3977 }
3978 }
3979
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003980 /**
3981 * Allow callers with the given uid permission to get credentials for account/authTokenType.
3982 * <p>
3983 * Although this is public it can only be accessed via the AccountManagerService object
3984 * which is in the system. This means we don't need to protect it with permissions.
3985 * @hide
3986 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07003987 private void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07003988 if (account == null || authTokenType == null) {
3989 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07003990 return;
3991 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003992 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003993 synchronized (accounts.cacheLock) {
3994 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003995 db.beginTransaction();
3996 try {
3997 long accountId = getAccountIdLocked(db, account);
3998 if (accountId >= 0) {
3999 ContentValues values = new ContentValues();
4000 values.put(GRANTS_ACCOUNTS_ID, accountId);
4001 values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
4002 values.put(GRANTS_GRANTEE_UID, uid);
4003 db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
4004 db.setTransactionSuccessful();
4005 }
4006 } finally {
4007 db.endTransaction();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004008 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004009 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
4010 new UserHandle(accounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004011 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004012 }
4013
4014 /**
4015 * Don't allow callers with the given uid permission to get credentials for
4016 * account/authTokenType.
4017 * <p>
4018 * Although this is public it can only be accessed via the AccountManagerService object
4019 * which is in the system. This means we don't need to protect it with permissions.
4020 * @hide
4021 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07004022 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07004023 if (account == null || authTokenType == null) {
4024 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07004025 return;
4026 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07004027 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004028 synchronized (accounts.cacheLock) {
4029 final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004030 db.beginTransaction();
4031 try {
4032 long accountId = getAccountIdLocked(db, account);
4033 if (accountId >= 0) {
4034 db.delete(TABLE_GRANTS,
4035 GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
4036 + GRANTS_GRANTEE_UID + "=?",
4037 new String[]{String.valueOf(accountId), authTokenType,
4038 String.valueOf(uid)});
4039 db.setTransactionSuccessful();
4040 }
4041 } finally {
4042 db.endTransaction();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004043 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004044 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
4045 new UserHandle(accounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004046 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004047 }
Fred Quintana56285a62010-12-02 14:20:51 -08004048
4049 static final private String stringArrayToString(String[] value) {
4050 return value != null ? ("[" + TextUtils.join(",", value) + "]") : null;
4051 }
4052
Amith Yamasani04e0d262012-02-14 11:50:53 -08004053 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
4054 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004055 if (oldAccountsForType != null) {
4056 ArrayList<Account> newAccountsList = new ArrayList<Account>();
4057 for (Account curAccount : oldAccountsForType) {
4058 if (!curAccount.equals(account)) {
4059 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08004060 }
4061 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004062 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004063 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004064 } else {
4065 Account[] newAccountsForType = new Account[newAccountsList.size()];
4066 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004067 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004068 }
Fred Quintana56285a62010-12-02 14:20:51 -08004069 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004070 accounts.userDataCache.remove(account);
4071 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004072 accounts.previousNameCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08004073 }
4074
4075 /**
4076 * This assumes that the caller has already checked that the account is not already present.
4077 */
Amith Yamasani04e0d262012-02-14 11:50:53 -08004078 private void insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
4079 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004080 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
4081 Account[] newAccountsForType = new Account[oldLength + 1];
4082 if (accountsForType != null) {
4083 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08004084 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004085 newAccountsForType[oldLength] = account;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004086 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08004087 }
4088
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004089 private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
Amith Yamasani27db4682013-03-30 17:07:47 -07004090 int callingUid, String callingPackage) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004091 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Amith Yamasani27db4682013-03-30 17:07:47 -07004092 || callingUid == Process.myUid()) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004093 return unfiltered;
4094 }
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004095 UserInfo user = mUserManager.getUserInfo(userAccounts.userId);
4096 if (user != null && user.isRestricted()) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004097 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07004098 // If any of the packages is a white listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004099 // otherwise return non-shared accounts only.
4100 // This might be a temporary way to specify a whitelist
4101 String whiteList = mContext.getResources().getString(
4102 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
4103 for (String packageName : packages) {
4104 if (whiteList.contains(";" + packageName + ";")) {
4105 return unfiltered;
4106 }
4107 }
4108 ArrayList<Account> allowed = new ArrayList<Account>();
4109 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
4110 if (sharedAccounts == null || sharedAccounts.length == 0) return unfiltered;
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07004111 String requiredAccountType = "";
4112 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07004113 // If there's an explicit callingPackage specified, check if that package
4114 // opted in to see restricted accounts.
4115 if (callingPackage != null) {
4116 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07004117 if (pi != null && pi.restrictedAccountType != null) {
4118 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07004119 }
4120 } else {
4121 // Otherwise check if the callingUid has a package that has opted in
4122 for (String packageName : packages) {
4123 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
4124 if (pi != null && pi.restrictedAccountType != null) {
4125 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07004126 break;
4127 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004128 }
4129 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07004130 } catch (NameNotFoundException nnfe) {
4131 }
4132 for (Account account : unfiltered) {
4133 if (account.type.equals(requiredAccountType)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004134 allowed.add(account);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07004135 } else {
4136 boolean found = false;
4137 for (Account shared : sharedAccounts) {
4138 if (shared.equals(account)) {
4139 found = true;
4140 break;
4141 }
4142 }
4143 if (!found) {
4144 allowed.add(account);
4145 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004146 }
4147 }
4148 Account[] filtered = new Account[allowed.size()];
4149 allowed.toArray(filtered);
4150 return filtered;
4151 } else {
4152 return unfiltered;
4153 }
4154 }
4155
Amith Yamasani27db4682013-03-30 17:07:47 -07004156 /*
4157 * packageName can be null. If not null, it should be used to filter out restricted accounts
4158 * that the package is not allowed to access.
4159 */
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004160 protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
Amith Yamasani27db4682013-03-30 17:07:47 -07004161 int callingUid, String callingPackage) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004162 if (accountType != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004163 final Account[] accounts = userAccounts.accountCache.get(accountType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004164 if (accounts == null) {
4165 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08004166 } else {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004167 return filterSharedAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
Amith Yamasani27db4682013-03-30 17:07:47 -07004168 callingUid, callingPackage);
Fred Quintana56285a62010-12-02 14:20:51 -08004169 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004170 } else {
4171 int totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004172 for (Account[] accounts : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004173 totalLength += accounts.length;
4174 }
4175 if (totalLength == 0) {
4176 return EMPTY_ACCOUNT_ARRAY;
4177 }
4178 Account[] accounts = new Account[totalLength];
4179 totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004180 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004181 System.arraycopy(accountsOfType, 0, accounts, totalLength,
4182 accountsOfType.length);
4183 totalLength += accountsOfType.length;
4184 }
Amith Yamasani27db4682013-03-30 17:07:47 -07004185 return filterSharedAccounts(userAccounts, accounts, callingUid, callingPackage);
Fred Quintana56285a62010-12-02 14:20:51 -08004186 }
4187 }
4188
Amith Yamasani04e0d262012-02-14 11:50:53 -08004189 protected void writeUserDataIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
4190 Account account, String key, String value) {
4191 HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004192 if (userDataForAccount == null) {
4193 userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004194 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004195 }
4196 if (value == null) {
4197 userDataForAccount.remove(key);
4198 } else {
4199 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08004200 }
4201 }
4202
Carlos Valdivia91979be2015-05-22 14:11:35 -07004203 protected String readCachedTokenInternal(
4204 UserAccounts accounts,
4205 Account account,
4206 String tokenType,
4207 String callingPackage,
4208 byte[] pkgSigDigest) {
4209 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004210 return accounts.accountTokenCaches.get(
4211 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004212 }
4213 }
4214
Amith Yamasani04e0d262012-02-14 11:50:53 -08004215 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
4216 Account account, String key, String value) {
4217 HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004218 if (authTokensForAccount == null) {
4219 authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004220 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004221 }
4222 if (value == null) {
4223 authTokensForAccount.remove(key);
4224 } else {
4225 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08004226 }
4227 }
4228
Amith Yamasani04e0d262012-02-14 11:50:53 -08004229 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
4230 String authTokenType) {
4231 synchronized (accounts.cacheLock) {
4232 HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintana56285a62010-12-02 14:20:51 -08004233 if (authTokensForAccount == null) {
4234 // need to populate the cache for this account
Amith Yamasani04e0d262012-02-14 11:50:53 -08004235 final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004236 authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004237 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08004238 }
4239 return authTokensForAccount.get(authTokenType);
4240 }
4241 }
4242
Amith Yamasani04e0d262012-02-14 11:50:53 -08004243 protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
4244 synchronized (accounts.cacheLock) {
4245 HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintana56285a62010-12-02 14:20:51 -08004246 if (userDataForAccount == null) {
4247 // need to populate the cache for this account
Amith Yamasani04e0d262012-02-14 11:50:53 -08004248 final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004249 userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004250 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08004251 }
4252 return userDataForAccount.get(key);
4253 }
4254 }
4255
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004256 protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
4257 final SQLiteDatabase db, Account account) {
Fred Quintana56285a62010-12-02 14:20:51 -08004258 HashMap<String, String> userDataForAccount = new HashMap<String, String>();
Fred Quintana56285a62010-12-02 14:20:51 -08004259 Cursor cursor = db.query(TABLE_EXTRAS,
4260 COLUMNS_EXTRAS_KEY_AND_VALUE,
4261 SELECTION_USERDATA_BY_ACCOUNT,
4262 new String[]{account.name, account.type},
4263 null, null, null);
4264 try {
4265 while (cursor.moveToNext()) {
4266 final String tmpkey = cursor.getString(0);
4267 final String value = cursor.getString(1);
4268 userDataForAccount.put(tmpkey, value);
4269 }
4270 } finally {
4271 cursor.close();
4272 }
4273 return userDataForAccount;
4274 }
4275
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004276 protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
4277 final SQLiteDatabase db, Account account) {
Fred Quintana56285a62010-12-02 14:20:51 -08004278 HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
Fred Quintana56285a62010-12-02 14:20:51 -08004279 Cursor cursor = db.query(TABLE_AUTHTOKENS,
4280 COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
4281 SELECTION_AUTHTOKENS_BY_ACCOUNT,
4282 new String[]{account.name, account.type},
4283 null, null, null);
4284 try {
4285 while (cursor.moveToNext()) {
4286 final String type = cursor.getString(0);
4287 final String authToken = cursor.getString(1);
4288 authTokensForAccount.put(type, authToken);
4289 }
4290 } finally {
4291 cursor.close();
4292 }
4293 return authTokensForAccount;
4294 }
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004295
4296 private Context getContextForUser(UserHandle user) {
4297 try {
4298 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
4299 } catch (NameNotFoundException e) {
4300 // Default to mContext, not finding the package system is running as is unlikely.
4301 return mContext;
4302 }
4303 }
Fred Quintana60307342009-03-24 22:48:12 -07004304}