blob: ec4dc64ec4b0311db953f95d89cdcf2e0b9feb62 [file] [log] [blame]
Fred Quintana60307342009-03-24 22:48:12 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.accounts;
Fred Quintana60307342009-03-24 22:48:12 -070018
Doug Zongker885cfc232009-10-21 16:52:44 -070019import android.Manifest;
Carlos Valdivia91979be2015-05-22 14:11:35 -070020import android.accounts.AbstractAccountAuthenticator;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080021import android.accounts.Account;
22import android.accounts.AccountAndUser;
23import android.accounts.AccountAuthenticatorResponse;
24import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070025import android.accounts.AccountManagerInternal;
sunjianf29d5492017-05-11 15:42:31 -070026import android.accounts.AccountManagerResponse;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080027import android.accounts.AuthenticatorDescription;
Amith Yamasani23c8b962013-04-10 13:37:18 -070028import android.accounts.CantAddAccountActivity;
sunjianf29d5492017-05-11 15:42:31 -070029import android.accounts.ChooseAccountActivity;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080030import android.accounts.GrantCredentialsPermissionActivity;
31import android.accounts.IAccountAuthenticator;
32import android.accounts.IAccountAuthenticatorResponse;
33import android.accounts.IAccountManager;
34import android.accounts.IAccountManagerResponse;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070035import android.annotation.IntRange;
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070036import android.annotation.NonNull;
Svet Ganovf6d424f12016-09-20 20:18:53 -070037import android.annotation.Nullable;
Brett Chabot3b4fcbc2011-01-09 13:41:02 -080038import android.app.ActivityManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070039import android.app.ActivityThread;
Svetoslavf3f02ac2015-09-08 14:36:35 -070040import android.app.AppOpsManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070041import android.app.INotificationManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070042import android.app.Notification;
43import android.app.NotificationManager;
44import android.app.PendingIntent;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000045import android.app.admin.DeviceAdminInfo;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010046import android.app.admin.DevicePolicyManager;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000047import android.app.admin.DevicePolicyManagerInternal;
Fred Quintanaa698f422009-04-08 19:14:54 -070048import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070049import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070050import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070053import android.content.IntentSender;
Fred Quintanab839afc2009-10-14 15:57:28 -070054import android.content.ServiceConnection;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -080055import android.content.pm.ActivityInfo;
Doug Zongker885cfc232009-10-21 16:52:44 -070056import android.content.pm.ApplicationInfo;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070057import android.content.pm.IPackageManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070058import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070059import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070060import android.content.pm.PackageManager.NameNotFoundException;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070061import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070062import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070063import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070064import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070065import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070066import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070067import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070068import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070069import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080070import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070071import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070072import android.os.IBinder;
73import android.os.Looper;
74import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070075import android.os.Parcel;
sunjianf29d5492017-05-11 15:42:31 -070076import android.os.Parcelable;
Amith Yamasani27db4682013-03-30 17:07:47 -070077import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070078import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070079import android.os.RemoteException;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080080import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070081import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070082import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070083import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070084import android.text.TextUtils;
85import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070086import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070087import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080088import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070089import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070090
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070091import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070092import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070093import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070094import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040095import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050096import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080097import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060098import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080099import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -0700100import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +0000101import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700102import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600103import com.android.server.SystemService;
104
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700105import com.google.android.collect.Lists;
106import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700107
Oscar Montemayora8529f62009-11-18 10:14:20 -0800108import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700109import java.io.FileDescriptor;
110import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800111import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700112import java.security.MessageDigest;
113import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700114import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700115import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800116import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700117import java.util.Collection;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700118import java.util.Collections;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700119import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700120import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700121import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800122import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700123import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800124import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800125import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700126import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700127import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700128import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700129import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700130import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700131
Fred Quintana60307342009-03-24 22:48:12 -0700132/**
133 * A system service that provides account, password, and authtoken management for all
134 * accounts on the device. Some of these calls are implemented with the help of the corresponding
135 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
136 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700137 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700138 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700139 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700140public class AccountManagerService
141 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800142 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700143 private static final String TAG = "AccountManagerService";
144
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600145 public static class Lifecycle extends SystemService {
146 private AccountManagerService mService;
147
148 public Lifecycle(Context context) {
149 super(context);
150 }
151
152 @Override
153 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700154 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600155 publishBinderService(Context.ACCOUNT_SERVICE, mService);
156 }
157
158 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600159 public void onUnlockUser(int userHandle) {
160 mService.onUnlockUser(userHandle);
161 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700162
163 @Override
Fyodor Kupolovce25ed22017-05-04 11:44:31 -0700164 public void onStopUser(int userHandle) {
165 mService.onStopUser(userHandle);
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700166 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600167 }
168
Svet Ganov5d09c992016-09-07 09:57:41 -0700169 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700170
Fred Quintana56285a62010-12-02 14:20:51 -0800171 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700172 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700173 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700174 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800175
Svet Ganov5d09c992016-09-07 09:57:41 -0700176 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700177
Fred Quintana60307342009-03-24 22:48:12 -0700178 // Messages that can be sent on mHandler
179 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700180 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700181
Fred Quintana56285a62010-12-02 14:20:51 -0800182 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700183 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700184 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800185
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800186 private static final int SIGNATURE_CHECK_MISMATCH = 0;
187 private static final int SIGNATURE_CHECK_MATCH = 1;
188 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
189
Carlos Valdivia91979be2015-05-22 14:11:35 -0700190 static {
191 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800192 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
193 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700194 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700195
196 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700197
Amith Yamasani04e0d262012-02-14 11:50:53 -0800198 static class UserAccounts {
199 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700200 final AccountsDb accountsDb;
Chris Wren717a8812017-03-31 15:34:39 -0400201 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
202 credentialsPermissionNotificationIds = new HashMap<>();
203 private final HashMap<Account, NotificationId> signinRequiredNotificationIds
204 = new HashMap<>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700205 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700206 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800207 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700208 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800209 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700210 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800211 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700212 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700213 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700214 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700215 /** protected by the {@link #cacheLock} */
216 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700217
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700218 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700219 * type -> (packageName -> number of active receivers)
220 * type == null is used to get notifications about all account types
221 */
222 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800223
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700224 /**
225 * protected by the {@link #cacheLock}
226 *
227 * Caches the previous names associated with an account. Previous names
228 * should be cached because we expect that when an Account is renamed,
229 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
230 * want to know if the accounts they care about have been renamed.
231 *
232 * The previous names are wrapped in an {@link AtomicReference} so that
233 * we can distinguish between those accounts with no previous names and
234 * those whose previous names haven't been cached (yet).
235 */
236 private final HashMap<Account, AtomicReference<String>> previousNameCache =
237 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800238
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700239 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700240 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700241
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700242 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800243 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700244 synchronized (dbLock) {
245 synchronized (cacheLock) {
246 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
247 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800248 }
249 }
250 }
251
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700252 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600253 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700254 // Not thread-safe. Only use in synchronized context
255 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700256 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
257 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800258
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700259 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700260 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700261
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700262 /**
263 * This should only be called by system code. One should only call this after the service
264 * has started.
265 * @return a reference to the AccountManagerService instance
266 * @hide
267 */
268 public static AccountManagerService getSingleton() {
269 return sThis.get();
270 }
Fred Quintana60307342009-03-24 22:48:12 -0700271
Fyodor Kupolovda993802016-09-21 14:47:10 -0700272 public AccountManagerService(Injector injector) {
273 mInjector = injector;
274 mContext = injector.getContext();
275 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700276 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700277 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
278 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800279 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700280
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700281 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800282
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800283 IntentFilter intentFilter = new IntentFilter();
284 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
285 intentFilter.addDataScheme("package");
286 mContext.registerReceiver(new BroadcastReceiver() {
287 @Override
288 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700289 // Don't delete accounts when updating a authenticator's
290 // package.
291 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700292 /* Purging data requires file io, don't block the main thread. This is probably
293 * less than ideal because we are introducing a race condition where old grants
294 * could be exercised until they are purged. But that race condition existed
295 * anyway with the broadcast receiver.
296 *
297 * Ideally, we would completely clear the cache, purge data from the database,
298 * and then rebuild the cache. All under the cache lock. But that change is too
299 * large at this point.
300 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800301 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700302 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700303 @Override
304 public void run() {
305 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800306 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800307 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700308 }
309 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700310 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700311 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800312 }
313 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800314
Fyodor Kupolovda993802016-09-21 14:47:10 -0700315 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700316
317 // Need to cancel account request notifications if the update/install can access the account
318 new PackageMonitor() {
319 @Override
320 public void onPackageAdded(String packageName, int uid) {
321 // Called on a handler, and running as the system
322 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
323 }
324
325 @Override
326 public void onPackageUpdateFinished(String packageName, int uid) {
327 // Called on a handler, and running as the system
328 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
329 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700330 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700331
332 // Cancel account request notification if an app op was preventing the account access
333 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
334 new AppOpsManager.OnOpChangedInternalListener() {
335 @Override
336 public void onOpChanged(int op, String packageName) {
337 try {
338 final int userId = ActivityManager.getCurrentUser();
339 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
340 final int mode = mAppOpsManager.checkOpNoThrow(
341 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
342 if (mode == AppOpsManager.MODE_ALLOWED) {
343 final long identity = Binder.clearCallingIdentity();
344 try {
345 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
346 } finally {
347 Binder.restoreCallingIdentity(identity);
348 }
349 }
350 } catch (NameNotFoundException e) {
351 /* ignore */
352 }
353 }
354 });
355
356 // Cancel account request notification if a permission was preventing the account access
357 mPackageManager.addOnPermissionsChangeListener(
358 (int uid) -> {
359 Account[] accounts = null;
360 String[] packageNames = mPackageManager.getPackagesForUid(uid);
361 if (packageNames != null) {
362 final int userId = UserHandle.getUserId(uid);
363 final long identity = Binder.clearCallingIdentity();
364 try {
365 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800366 // if app asked for permission we need to cancel notification even
367 // for O+ applications.
368 if (mPackageManager.checkPermission(
369 Manifest.permission.GET_ACCOUNTS,
370 packageName) != PackageManager.PERMISSION_GRANTED) {
371 continue;
372 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700373
374 if (accounts == null) {
375 accounts = getAccountsAsUser(null, userId, "android");
376 if (ArrayUtils.isEmpty(accounts)) {
377 return;
378 }
379 }
380
381 for (Account account : accounts) {
382 cancelAccountAccessRequestNotificationIfNeeded(
383 account, uid, packageName, true);
384 }
385 }
386 } finally {
387 Binder.restoreCallingIdentity(identity);
388 }
389 }
390 });
391 }
392
393 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
394 boolean checkAccess) {
395 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
396 for (Account account : accounts) {
397 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
398 }
399 }
400
401 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
402 boolean checkAccess) {
403 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
404 for (Account account : accounts) {
405 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
406 }
407 }
408
409 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
410 boolean checkAccess) {
411 String[] packageNames = mPackageManager.getPackagesForUid(uid);
412 if (packageNames != null) {
413 for (String packageName : packageNames) {
414 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
415 packageName, checkAccess);
416 }
417 }
418 }
419
420 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
421 int uid, String packageName, boolean checkAccess) {
422 if (!checkAccess || hasAccountAccess(account, packageName,
423 UserHandle.getUserHandleForUid(uid))) {
424 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700425 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700426 UserHandle.getUserHandleForUid(uid));
427 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800428 }
429
Dianne Hackborn164371f2013-10-01 19:10:13 -0700430 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800431 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800432 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800433 Bundle.setDefusable(extras, true);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700434 int callingUid = Binder.getCallingUid();
435 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800436 if (Log.isLoggable(TAG, Log.VERBOSE)) {
437 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
438 + ", pid " + Binder.getCallingPid());
439 }
440 Preconditions.checkNotNull(account, "account cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800441 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
442 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
443 callingUid, account.type);
444 throw new SecurityException(msg);
445 }
446 /*
447 * Child users are not allowed to add accounts. Only the accounts that are shared by the
448 * parent profile can be added to child profile.
449 *
450 * TODO: Only allow accounts that were shared to be added by a limited user.
451 */
452 // fails if the account already exists
453 long identityToken = clearCallingIdentity();
454 try {
455 UserAccounts accounts = getUserAccounts(userId);
456 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800457 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800458 } finally {
459 restoreCallingIdentity(identityToken);
460 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700461 }
462
463 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800464 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
465 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800466 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700467 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800468 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700469 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800470
471 if ((accountType != null && !managedTypes.contains(accountType))
472 || (accountType == null && !isSystemUid)) {
473 throw new SecurityException(
474 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
475 + callingUid + " with packageName=" + packageName);
476 }
477 if (accountType != null) {
478 managedTypes = new ArrayList<String>();
479 managedTypes.add(accountType);
480 }
481
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800482 long identityToken = clearCallingIdentity();
483 try {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700484 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800485 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700486 accounts);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800487 } finally {
488 restoreCallingIdentity(identityToken);
489 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800490 }
491
492 /*
493 * accountTypes may not be null
494 */
495 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
496 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700497 if (!packageExistsForUser(packageName, accounts.userId)) {
498 Log.d(TAG, "Package not found " + packageName);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800499 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800500 }
501
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800502 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800503 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700504 synchronized (accounts.dbLock) {
505 synchronized (accounts.cacheLock) {
506 final Account[] accountsOfType = accounts.accountCache.get(accountType);
507 if (accountsOfType != null) {
508 for (Account account : accountsOfType) {
509 result.put(account,
510 resolveAccountVisibility(account, packageName, accounts));
511 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800512 }
513 }
514 }
515 }
516 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800517 }
518
519 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800520 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700521 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700522 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700523 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800524 if (!isAccountManagedByCaller(account.type, callingUid, userId)
525 && !isSystemUid(callingUid)) {
526 String msg =
527 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700528 throw new SecurityException(msg);
529 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700530
531 long identityToken = clearCallingIdentity();
532 try {
533 UserAccounts accounts = getUserAccounts(userId);
534 synchronized (accounts.dbLock) {
535 synchronized (accounts.cacheLock) {
536 return getPackagesAndVisibilityForAccountLocked(account, accounts);
537 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700538 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700539 } finally {
540 restoreCallingIdentity(identityToken);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700541 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700542
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800543 }
544
545 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700546 * Returns Map with all package names and visibility values for given account.
547 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800548 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800549 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800550 * @param accounts UserAccount that currently hosts the account and application
551 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700552 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800553 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700554 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800555 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700556 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
557 if (accountVisibility == null) {
558 Log.d(TAG, "Visibility was not initialized");
559 accountVisibility = new HashMap<>();
560 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800561 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700562 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700563 }
564
565 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700566 public int getAccountVisibility(Account account, String packageName) {
567 Preconditions.checkNotNull(account, "account cannot be null");
568 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800569 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700570 int userId = UserHandle.getCallingUserId();
571 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800572 && !isSystemUid(callingUid)) {
573 String msg = String.format(
574 "uid %s cannot get secrets for accounts of type: %s",
575 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700576 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800577 throw new SecurityException(msg);
578 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700579 long identityToken = clearCallingIdentity();
580 try {
581 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyevcbe1bd12017-04-25 17:02:47 -0700582 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
583 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
584 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
585 return visibility;
586 } else {
587 return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
588 }
589 }
590 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) {
591 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
592 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
593 return visibility;
594 } else {
595 return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
596 }
597 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700598 return resolveAccountVisibility(account, packageName, accounts);
599 } finally {
600 restoreCallingIdentity(identityToken);
601 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800602 }
603
604 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800605 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800606 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800607 * @param account The account to check visibility.
608 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800609 * @param accounts UserAccount that currently hosts the account and application
610 *
611 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
612 *
613 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700614 private int getAccountVisibilityFromCache(Account account, String packageName,
615 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700616 synchronized (accounts.cacheLock) {
617 Map<String, Integer> accountVisibility =
618 getPackagesAndVisibilityForAccountLocked(account, accounts);
619 Integer visibility = accountVisibility.get(packageName);
620 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800621 }
622 }
623
624 /**
625 * Method which handles default values for Account visibility.
626 *
627 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800628 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800629 * @param accounts UserAccount that currently hosts the account and application
630 *
631 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
632 *
633 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800634 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800635 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800636 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800637 int uid = -1;
638 try {
639 long identityToken = clearCallingIdentity();
640 try {
641 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
642 } finally {
643 restoreCallingIdentity(identityToken);
644 }
645 } catch (NameNotFoundException e) {
646 Log.d(TAG, "Package not found " + e.getMessage());
647 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800648 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800649
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800650 // System visibility can not be restricted.
651 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
652 return AccountManager.VISIBILITY_VISIBLE;
653 }
654
655 int signatureCheckResult =
656 checkPackageSignature(account.type, uid, accounts.userId);
657
658 // Authenticator can not restrict visibility to itself.
659 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
660 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
661 }
662
663 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700664 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800665
666 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
667 return visibility;
668 }
669
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700670 boolean isPrivileged = isPermittedForPackage(packageName, uid, accounts.userId,
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800671 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
672
673 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800674 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800675 return AccountManager.VISIBILITY_VISIBLE;
676 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800677
678 boolean preO = isPreOApplication(packageName);
679 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700680 || (preO && checkGetAccountsPermission(packageName, uid, accounts.userId))
681 || (checkReadContactsPermission(packageName, uid, accounts.userId)
682 && accountTypeManagesContacts(account.type, accounts.userId))
683 || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800684 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
685 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700686 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800687 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800688 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
689 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
690 }
691 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700692 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800693 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800694 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
695 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
696 }
697 }
698 return visibility;
699 }
700
701 /**
702 * Checks targetSdk for a package;
703 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800704 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800705 *
706 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
707 * undefined
708 */
709 private boolean isPreOApplication(String packageName) {
710 try {
711 long identityToken = clearCallingIdentity();
712 ApplicationInfo applicationInfo;
713 try {
714 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
715 } finally {
716 restoreCallingIdentity(identityToken);
717 }
718
719 if (applicationInfo != null) {
720 int version = applicationInfo.targetSdkVersion;
721 return version < android.os.Build.VERSION_CODES.O;
722 }
723 return true;
724 } catch (NameNotFoundException e) {
725 Log.d(TAG, "Package not found " + e.getMessage());
726 return true;
727 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800728 }
729
730 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700731 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
732 Preconditions.checkNotNull(account, "account cannot be null");
733 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800734 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700735 int userId = UserHandle.getCallingUserId();
736 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800737 && !isSystemUid(callingUid)) {
738 String msg = String.format(
739 "uid %s cannot get secrets for accounts of type: %s",
740 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700741 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800742 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700743 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700744 long identityToken = clearCallingIdentity();
745 try {
746 UserAccounts accounts = getUserAccounts(userId);
747 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700748 accounts);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700749 } finally {
750 restoreCallingIdentity(identityToken);
751 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700752 }
753
754 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800755 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700756 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800757 * @param account Account to update visibility.
758 * @param packageName Package name for which visibility is updated.
759 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800760 * @param notify if the flag is set applications will get notification about visibility change
761 * @param accounts UserAccount that currently hosts the account and application
762 *
763 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700764 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800765 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800766 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700767 synchronized (accounts.dbLock) {
768 synchronized (accounts.cacheLock) {
769 Map<String, Integer> packagesToVisibility;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700770 List<String> accountRemovedReceivers;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700771 if (notify) {
772 if (isSpecialPackageKey(packageName)) {
773 packagesToVisibility =
774 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700775 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700776 } else {
777 if (!packageExistsForUser(packageName, accounts.userId)) {
778 return false; // package is not installed.
779 }
780 packagesToVisibility = new HashMap<>();
781 packagesToVisibility.put(packageName,
782 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700783 accountRemovedReceivers = new ArrayList<>();
784 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
785 accountRemovedReceivers.add(packageName);
786 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700787 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800788 } else {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700789 // Notifications will not be send - only used during add account.
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700790 if (!isSpecialPackageKey(packageName) &&
791 !packageExistsForUser(packageName, accounts.userId)) {
792 // package is not installed and not meta value.
793 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100794 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700795 packagesToVisibility = Collections.emptyMap();
796 accountRemovedReceivers = Collections.emptyList();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800797 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700798
799 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800800 return false;
801 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800802
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700803 if (notify) {
804 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
805 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700806 if (shouldNotifyOnVisibilityChange(packageToVisibility.getValue(),
807 resolveAccountVisibility(account, packageName, accounts))) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700808 notifyPackage(packageToVisibility.getKey(), accounts);
809 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700810 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700811 for (String packageNameToNotify : accountRemovedReceivers) {
812 sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
813 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700814 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700815 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700816 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800817 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700818 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700819 }
820
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700821 // Update account visibility in cache and database.
822 private boolean updateAccountVisibilityLocked(Account account, String packageName,
823 int newVisibility, UserAccounts accounts) {
824 final long accountId = accounts.accountsDb.findDeAccountId(account);
825 if (accountId < 0) {
826 return false;
827 }
828
829 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
830 try {
831 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
832 newVisibility)) {
833 return false;
834 }
835 } finally {
836 StrictMode.setThreadPolicy(oldPolicy);
837 }
838 Map<String, Integer> accountVisibility =
839 getPackagesAndVisibilityForAccountLocked(account, accounts);
840 accountVisibility.put(packageName, newVisibility);
841 return true;
842 }
843
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700844 @Override
845 public void registerAccountListener(String[] accountTypes, String opPackageName) {
846 int callingUid = Binder.getCallingUid();
847 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700848
849 int userId = UserHandle.getCallingUserId();
850 long identityToken = clearCallingIdentity();
851 try {
852 UserAccounts accounts = getUserAccounts(userId);
853 registerAccountListener(accountTypes, opPackageName, accounts);
854 } finally {
855 restoreCallingIdentity(identityToken);
856 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800857 }
858
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700859 private void registerAccountListener(String[] accountTypes, String opPackageName,
860 UserAccounts accounts) {
861 synchronized (accounts.mReceiversForType) {
862 if (accountTypes == null) {
863 // null for any type
864 accountTypes = new String[] {null};
865 }
866 for (String type : accountTypes) {
867 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
868 if (receivers == null) {
869 receivers = new HashMap<>();
870 accounts.mReceiversForType.put(type, receivers);
871 }
872 Integer cnt = receivers.get(opPackageName);
873 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800874 }
875 }
876 }
877
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700878 @Override
879 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
880 int callingUid = Binder.getCallingUid();
881 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700882 int userId = UserHandle.getCallingUserId();
883 long identityToken = clearCallingIdentity();
884 try {
885 UserAccounts accounts = getUserAccounts(userId);
886 unregisterAccountListener(accountTypes, opPackageName, accounts);
887 } finally {
888 restoreCallingIdentity(identityToken);
889 }
890 }
891
892 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
893 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700894 synchronized (accounts.mReceiversForType) {
895 if (accountTypes == null) {
896 // null for any type
897 accountTypes = new String[] {null};
898 }
899 for (String type : accountTypes) {
900 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
901 if (receivers == null || receivers.get(opPackageName) == null) {
902 throw new IllegalArgumentException("attempt to unregister wrong receiver");
903 }
904 Integer cnt = receivers.get(opPackageName);
905 if (cnt == 1) {
906 receivers.remove(opPackageName);
907 } else {
908 receivers.put(opPackageName, cnt - 1);
909 }
910 }
911 }
912 }
913
914 // Send notification to all packages which can potentially see the account
915 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
916 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700917
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700918 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700919 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
920 && (packageToVisibility.getValue()
921 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700922 notifyPackage(packageToVisibility.getKey(), accounts);
923 }
924 }
925 }
926
927 /**
928 * Sends a direct intent to a package, notifying it of account visibility change.
929 *
930 * @param packageName to send Account to
931 * @param accounts UserAccount that currently hosts the account
932 */
933 private void notifyPackage(String packageName, UserAccounts accounts) {
934 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
935 intent.setPackage(packageName);
936 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
937 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
938 }
939
940 // Returns a map from package name to visibility, for packages subscribed
941 // to notifications about any account type, or type of provided account
942 // account type or all types.
943 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
944 Set<String> packages = new HashSet<>();
945 synchronized (accounts.mReceiversForType) {
946 for (String type : new String[] {account.type, null}) {
947 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
948 if (receivers != null) {
949 packages.addAll(receivers.keySet());
950 }
951 }
952 }
953 Map<String, Integer> result = new HashMap<>();
954 for (String packageName : packages) {
955 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
956 }
957 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800958 }
959
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700960 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
961 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
962 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
963 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
964 List<ResolveInfo> receivers =
965 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
966 List<String> result = new ArrayList<>();
967 if (receivers == null) {
968 return result;
969 }
970 for (ResolveInfo resolveInfo: receivers) {
971 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
972 int visibility = resolveAccountVisibility(account, packageName, accounts);
973 if (visibility == AccountManager.VISIBILITY_VISIBLE
974 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
975 result.add(packageName);
976 }
977 }
978 return result;
979 }
980
981 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
982 private boolean shouldNotifyPackageOnAccountRemoval(Account account,
983 String packageName, UserAccounts accounts) {
984 int visibility = resolveAccountVisibility(account, packageName, accounts);
985 if (visibility != AccountManager.VISIBILITY_VISIBLE
986 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
987 return false;
988 }
989
990 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
991 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
992 intent.setPackage(packageName);
993 List<ResolveInfo> receivers =
994 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
995 return (receivers != null && receivers.size() > 0);
996 }
997
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800998 private boolean packageExistsForUser(String packageName, int userId) {
999 try {
1000 long identityToken = clearCallingIdentity();
1001 try {
1002 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -07001003 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001004 } finally {
1005 restoreCallingIdentity(identityToken);
1006 }
1007 } catch (NameNotFoundException e) {
1008 return false;
1009 }
1010 }
1011
1012 /**
1013 * Returns true if packageName is one of special values.
1014 */
1015 private boolean isSpecialPackageKey(String packageName) {
1016 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1017 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1018 }
1019
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001020 private void sendAccountsChangedBroadcast(int userId) {
1021 Log.i(TAG, "the accounts changed, sending broadcast of "
1022 + ACCOUNTS_CHANGED_INTENT.getAction());
1023 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001024 }
1025
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001026 private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001027 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1028 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001029 intent.setPackage(packageName);
1030 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1031 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001032 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1033 }
1034
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001035 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -07001036 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1037 throws RemoteException {
1038 try {
1039 return super.onTransact(code, data, reply, flags);
1040 } catch (RuntimeException e) {
1041 // The account manager only throws security exceptions, so let's
1042 // log all others.
1043 if (!(e instanceof SecurityException)) {
1044 Slog.wtf(TAG, "Account Manager Crash", e);
1045 }
1046 throw e;
1047 }
1048 }
1049
Amith Yamasani258848d2012-08-10 17:06:33 -07001050 private UserManager getUserManager() {
1051 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -07001052 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -07001053 }
1054 return mUserManager;
1055 }
1056
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001057 /**
1058 * Validate internal set of accounts against installed authenticators for
1059 * given user. Clears cached authenticators before validating.
1060 */
1061 public void validateAccounts(int userId) {
1062 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001063 // Invalidate user-specific cache to make sure we catch any
1064 // removed authenticators.
1065 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1066 }
1067
1068 /**
1069 * Validate internal set of accounts against installed authenticators for
1070 * given user. Clear cached authenticators before validating when requested.
1071 */
1072 private void validateAccountsInternal(
1073 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001074 if (Log.isLoggable(TAG, Log.DEBUG)) {
1075 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001076 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001077 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001078 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001079
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001080 if (invalidateAuthenticatorCache) {
1081 mAuthenticatorCache.invalidateCache(accounts.userId);
1082 }
1083
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001084 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1085 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001086 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001087
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001088 synchronized (accounts.dbLock) {
1089 synchronized (accounts.cacheLock) {
1090 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001091
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001092 // Get a map of stored authenticator types to UID
1093 final AccountsDb accountsDb = accounts.accountsDb;
1094 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1095 // Create a list of authenticator type whose previous uid no longer exists
1096 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1097 SparseBooleanArray knownUids = null;
1098 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1099 String type = authToUidEntry.getKey();
1100 int uid = authToUidEntry.getValue();
1101 Integer knownUid = knownAuth.get(type);
1102 if (knownUid != null && uid == knownUid) {
1103 // Remove it from the knownAuth list if it's unchanged.
1104 knownAuth.remove(type);
1105 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001106 /*
1107 * The authenticator is presently not cached and should only be triggered
1108 * when we think an authenticator has been removed (or is being updated).
1109 * But we still want to check if any data with the associated uid is
1110 * around. This is an (imperfect) signal that the package may be updating.
1111 *
1112 * A side effect of this is that an authenticator sharing a uid with
1113 * multiple apps won't get its credentials wiped as long as some app with
1114 * that uid is still on the device. But I suspect that this is a rare case.
1115 * And it isn't clear to me how an attacker could really exploit that
1116 * feature.
1117 *
1118 * The upshot is that we don't have to worry about accounts getting
1119 * uninstalled while the authenticator's package is being updated.
1120 *
1121 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001122 if (knownUids == null) {
1123 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1124 }
1125 if (!knownUids.get(uid)) {
1126 // The authenticator is not presently available to the cache. And the
1127 // package no longer has a data directory (so we surmise it isn't
1128 // updating). So purge its data from the account databases.
1129 obsoleteAuthType.add(type);
1130 // And delete it from the TABLE_META
1131 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1132 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001133 }
1134 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001135
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001136 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1137 // been re-enabled (after being updated for example), then we just overwrite the old
1138 // values.
1139 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1140 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1141 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001142
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001143 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1144 try {
1145 accounts.accountCache.clear();
1146 final HashMap<String, ArrayList<String>> accountNamesByType
1147 = new LinkedHashMap<>();
1148 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1149 final long accountId = accountEntry.getKey();
1150 final Account account = accountEntry.getValue();
1151 if (obsoleteAuthType.contains(account.type)) {
1152 Slog.w(TAG, "deleting account " + account.name + " because type "
1153 + account.type
1154 + "'s registered authenticator no longer exist.");
1155 Map<String, Integer> packagesToVisibility =
1156 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001157 List<String> accountRemovedReceivers =
1158 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001159 accountsDb.beginTransaction();
1160 try {
1161 accountsDb.deleteDeAccount(accountId);
1162 // Also delete from CE table if user is unlocked; if user is
1163 // currently locked the account will be removed later by
1164 // syncDeCeAccountsLocked
1165 if (userUnlocked) {
1166 accountsDb.deleteCeAccount(accountId);
1167 }
1168 accountsDb.setTransactionSuccessful();
1169 } finally {
1170 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001171 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001172 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001173
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001174 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1175 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001176
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001177 accounts.userDataCache.remove(account);
1178 accounts.authTokenCache.remove(account);
1179 accounts.accountTokenCaches.remove(account);
1180 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001181
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001182 for (Entry<String, Integer> packageToVisibility :
1183 packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001184 if (shouldNotifyOnVisibilityChange(packageToVisibility.getValue(),
1185 AccountManager.VISIBILITY_NOT_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001186 notifyPackage(packageToVisibility.getKey(), accounts);
1187 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001188 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001189 for (String packageName : accountRemovedReceivers) {
1190 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1191 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001192 } else {
1193 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1194 if (accountNames == null) {
1195 accountNames = new ArrayList<>();
1196 accountNamesByType.put(account.type, accountNames);
1197 }
1198 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001199 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001200 }
1201 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1202 final String accountType = cur.getKey();
1203 final ArrayList<String> accountNames = cur.getValue();
1204 final Account[] accountsForType = new Account[accountNames.size()];
1205 for (int i = 0; i < accountsForType.length; i++) {
1206 accountsForType[i] = new Account(accountNames.get(i), accountType,
1207 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001208 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001209 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001210 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001211 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1212 } finally {
1213 if (accountDeleted) {
1214 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001215 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001216 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001217 }
1218 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001219 }
1220
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001221 private boolean shouldNotifyOnVisibilityChange(int oldVisibility, int newVisibility) {
1222 boolean oldVisible = (oldVisibility == AccountManager.VISIBILITY_VISIBLE) ||
1223 (oldVisibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
1224 boolean newVisible = (newVisibility == AccountManager.VISIBILITY_VISIBLE) ||
1225 (newVisibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
1226 return oldVisible == newVisible;
1227 }
1228
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001229 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1230 // Get the UIDs of all apps that might have data on the device. We want
1231 // to preserve user data if the app might otherwise be storing data.
1232 List<PackageInfo> pkgsWithData =
1233 mPackageManager.getInstalledPackagesAsUser(
1234 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1235 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1236 for (PackageInfo pkgInfo : pkgsWithData) {
1237 if (pkgInfo.applicationInfo != null
1238 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1239 knownUids.put(pkgInfo.applicationInfo.uid, true);
1240 }
1241 }
1242 return knownUids;
1243 }
1244
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001245 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001246 Context context,
1247 int userId) {
1248 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001249 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1250 }
1251
1252 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1253 IAccountAuthenticatorCache authCache,
1254 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001255 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001256 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1257 .getAllServices(userId)) {
1258 knownAuth.put(service.type.type, service.uid);
1259 }
1260 return knownAuth;
1261 }
1262
Amith Yamasani04e0d262012-02-14 11:50:53 -08001263 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001264 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001265 }
1266
1267 protected UserAccounts getUserAccounts(int userId) {
1268 synchronized (mUsers) {
1269 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001270 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001271 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001272 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1273 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001274 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001275 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001276 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001277 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001278 validateAccounts = true;
1279 }
1280 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001281 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001282 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001283 synchronized (accounts.dbLock) {
1284 synchronized (accounts.cacheLock) {
1285 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1286 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1287 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001288 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001289 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001290 }
1291 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001292 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001293 }
1294 return accounts;
1295 }
1296 }
1297
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001298 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1299 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001300 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001301 if (!accountsToRemove.isEmpty()) {
1302 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1303 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001304 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1305 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001306
1307 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001308 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001309 }
1310 }
1311 }
1312
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001313 private void purgeOldGrantsAll() {
1314 synchronized (mUsers) {
1315 for (int i = 0; i < mUsers.size(); i++) {
1316 purgeOldGrants(mUsers.valueAt(i));
1317 }
1318 }
1319 }
1320
1321 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001322 synchronized (accounts.dbLock) {
1323 synchronized (accounts.cacheLock) {
1324 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1325 for (int uid : uids) {
1326 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1327 if (packageExists) {
1328 continue;
1329 }
1330 Log.d(TAG, "deleting grants for UID " + uid
1331 + " because its package is no longer installed");
1332 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001333 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001334 }
1335 }
1336 }
1337
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001338 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001339 if (isSpecialPackageKey(packageName)) {
1340 return;
1341 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001342 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001343 int numberOfUsers = mUsers.size();
1344 for (int i = 0; i < numberOfUsers; i++) {
1345 UserAccounts accounts = mUsers.valueAt(i);
1346 try {
1347 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1348 } catch (NameNotFoundException e) {
1349 // package does not exist - remove visibility values
1350 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001351 synchronized (accounts.dbLock) {
1352 synchronized (accounts.cacheLock) {
1353 for (Account account : accounts.visibilityCache.keySet()) {
1354 Map<String, Integer> accountVisibility =
1355 getPackagesAndVisibilityForAccountLocked(account, accounts);
1356 accountVisibility.remove(packageName);
1357 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001358 }
1359 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001360 }
1361 }
1362 }
1363 }
1364
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001365
Fyodor Kupolovce25ed22017-05-04 11:44:31 -07001366 private void onStopUser(int userId) {
1367 Log.i(TAG, "onStopUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001368 UserAccounts accounts;
1369 synchronized (mUsers) {
1370 accounts = mUsers.get(userId);
1371 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001372 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001373 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001374 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001375 synchronized (accounts.dbLock) {
1376 synchronized (accounts.cacheLock) {
1377 accounts.accountsDb.close();
1378 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001379 }
Amith Yamasani13593602012-03-22 16:16:17 -07001380 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001381 }
1382
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001383 @VisibleForTesting
1384 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001385 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1386 }
1387
1388 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001389 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1390 Log.v(TAG, "onUserUnlocked " + userId);
1391 }
1392 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001393 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001394 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001395 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001396 syncSharedAccounts(userId);
1397 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001398
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001399 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001400 // Check if there's a shared account that needs to be created as an account
1401 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1402 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001403 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001404 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001405 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001406 : UserHandle.USER_SYSTEM;
1407 if (parentUserId < 0) {
1408 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1409 return;
1410 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001411 for (Account sa : sharedAccounts) {
1412 if (ArrayUtils.contains(accounts, sa)) continue;
1413 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001414 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001415 }
1416 }
1417
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001418 @Override
1419 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001420 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001421 }
1422
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001423 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001424 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001425 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001426 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1427 Log.v(TAG, "getPassword: " + account
1428 + ", caller's uid " + Binder.getCallingUid()
1429 + ", pid " + Binder.getCallingPid());
1430 }
Fred Quintana382601f2010-03-25 12:25:10 -07001431 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001432 int userId = UserHandle.getCallingUserId();
1433 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001434 String msg = String.format(
1435 "uid %s cannot get secrets for accounts of type: %s",
1436 callingUid,
1437 account.type);
1438 throw new SecurityException(msg);
1439 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001440 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001441 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001442 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001443 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001444 } finally {
1445 restoreCallingIdentity(identityToken);
1446 }
1447 }
1448
Amith Yamasani04e0d262012-02-14 11:50:53 -08001449 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001450 if (account == null) {
1451 return null;
1452 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001453 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001454 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1455 return null;
1456 }
Fred Quintana31957f12009-10-21 13:43:10 -07001457
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001458 synchronized (accounts.dbLock) {
1459 synchronized (accounts.cacheLock) {
1460 return accounts.accountsDb
1461 .findAccountPasswordByNameAndType(account.name, account.type);
1462 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001463 }
1464 }
1465
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001466 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001467 public String getPreviousName(Account account) {
1468 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1469 Log.v(TAG, "getPreviousName: " + account
1470 + ", caller's uid " + Binder.getCallingUid()
1471 + ", pid " + Binder.getCallingPid());
1472 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001473 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001474 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001475 long identityToken = clearCallingIdentity();
1476 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001477 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001478 return readPreviousNameInternal(accounts, account);
1479 } finally {
1480 restoreCallingIdentity(identityToken);
1481 }
1482 }
1483
1484 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1485 if (account == null) {
1486 return null;
1487 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001488 synchronized (accounts.dbLock) {
1489 synchronized (accounts.cacheLock) {
1490 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1491 if (previousNameRef == null) {
1492 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1493 previousNameRef = new AtomicReference<>(previousName);
1494 accounts.previousNameCache.put(account, previousNameRef);
1495 return previousName;
1496 } else {
1497 return previousNameRef.get();
1498 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001499 }
1500 }
1501 }
1502
1503 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001504 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001505 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001506 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001507 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1508 account, key, callingUid, Binder.getCallingPid());
1509 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001510 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001511 Preconditions.checkNotNull(account, "account cannot be null");
1512 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001513 int userId = UserHandle.getCallingUserId();
1514 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001515 String msg = String.format(
1516 "uid %s cannot get user data for accounts of type: %s",
1517 callingUid,
1518 account.type);
1519 throw new SecurityException(msg);
1520 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001521 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001522 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1523 return null;
1524 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001525 long identityToken = clearCallingIdentity();
1526 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001527 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001528 if (!accountExistsCache(accounts, account)) {
1529 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001530 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001531 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001532 } finally {
1533 restoreCallingIdentity(identityToken);
1534 }
1535 }
1536
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001537 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001538 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001539 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001540 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1541 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001542 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001543 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001544 + ", pid " + Binder.getCallingPid());
1545 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001546 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001547 if (isCrossUser(callingUid, userId)) {
1548 throw new SecurityException(
1549 String.format(
1550 "User %s tying to get authenticator types for %s" ,
1551 UserHandle.getCallingUserId(),
1552 userId));
1553 }
1554
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001555 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001556 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001557 return getAuthenticatorTypesInternal(userId);
1558
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001559 } finally {
1560 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001561 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001562 }
1563
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001564 /**
1565 * Should only be called inside of a clearCallingIdentity block.
1566 */
1567 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001568 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001569 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1570 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1571 AuthenticatorDescription[] types =
1572 new AuthenticatorDescription[authenticatorCollection.size()];
1573 int i = 0;
1574 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1575 : authenticatorCollection) {
1576 types[i] = authenticator.type;
1577 i++;
1578 }
1579 return types;
1580 }
1581
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001582 private boolean isCrossUser(int callingUid, int userId) {
1583 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001584 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001585 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001586 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1587 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001588 }
1589
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001590 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001591 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001592 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001593 }
1594
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001595 @Override
1596 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001597 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001598 int callingUid = Binder.getCallingUid();
1599 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1600 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001601 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001602 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001603 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1604 final UserAccounts toAccounts = getUserAccounts(userTo);
1605 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001606 if (response != null) {
1607 Bundle result = new Bundle();
1608 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1609 try {
1610 response.onResult(result);
1611 } catch (RemoteException e) {
1612 Slog.w(TAG, "Failed to report error back to the client." + e);
1613 }
1614 }
1615 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001616 }
1617
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001618 Slog.d(TAG, "Copying account " + account.name
1619 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001620 long identityToken = clearCallingIdentity();
1621 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001622 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001623 false /* stripAuthTokenFromResult */, account.name,
1624 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001625 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001626 protected String toDebugString(long now) {
1627 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1628 + ", " + account.type;
1629 }
1630
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001631 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001632 public void run() throws RemoteException {
1633 mAuthenticator.getAccountCredentialsForCloning(this, account);
1634 }
1635
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001636 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001637 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001638 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001639 if (result != null
1640 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1641 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001642 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001643 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001644 super.onResult(result);
1645 }
1646 }
1647 }.bind();
1648 } finally {
1649 restoreCallingIdentity(identityToken);
1650 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001651 }
1652
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001653 @Override
1654 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001655 final int callingUid = Binder.getCallingUid();
1656 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1657 String msg = String.format(
1658 "accountAuthenticated( account: %s, callerUid: %s)",
1659 account,
1660 callingUid);
1661 Log.v(TAG, msg);
1662 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001663 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001664 int userId = UserHandle.getCallingUserId();
1665 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001666 String msg = String.format(
1667 "uid %s cannot notify authentication for accounts of type: %s",
1668 callingUid,
1669 account.type);
1670 throw new SecurityException(msg);
1671 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001672
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001673 if (!canUserModifyAccounts(userId, callingUid) ||
1674 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001675 return false;
1676 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001677
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001678 long identityToken = clearCallingIdentity();
1679 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001680 UserAccounts accounts = getUserAccounts(userId);
1681 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001682 } finally {
1683 restoreCallingIdentity(identityToken);
1684 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001685 }
1686
1687 private boolean updateLastAuthenticatedTime(Account account) {
1688 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001689 synchronized (accounts.dbLock) {
1690 synchronized (accounts.cacheLock) {
1691 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1692 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001693 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001694 }
1695
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001696 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001697 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1698 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001699 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001700 long id = clearCallingIdentity();
1701 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001702 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001703 false /* stripAuthTokenFromResult */, account.name,
1704 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001705 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001706 protected String toDebugString(long now) {
1707 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1708 + ", " + account.type;
1709 }
1710
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001711 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001712 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001713 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001714 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1715 if (acc.equals(account)) {
1716 mAuthenticator.addAccountFromCredentials(
1717 this, account, accountCredentials);
1718 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001719 }
1720 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001721 }
1722
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001723 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001724 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001725 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001726 // TODO: Anything to do if if succedded?
1727 // TODO: If it failed: Show error notification? Should we remove the shadow
1728 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001729 // TODO: what we do with the visibility?
1730
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001731 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001732 }
1733
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001734 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001735 public void onError(int errorCode, String errorMessage) {
1736 super.onError(errorCode, errorMessage);
1737 // TODO: Show error notification to user
1738 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1739 }
1740
1741 }.bind();
1742 } finally {
1743 restoreCallingIdentity(id);
1744 }
1745 }
1746
Amith Yamasani04e0d262012-02-14 11:50:53 -08001747 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001748 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001749 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001750 if (account == null) {
1751 return false;
1752 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001753 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001754 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1755 + " is locked. callingUid=" + callingUid);
1756 return false;
1757 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001758 synchronized (accounts.dbLock) {
1759 synchronized (accounts.cacheLock) {
1760 accounts.accountsDb.beginTransaction();
1761 try {
1762 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1763 Log.w(TAG, "insertAccountIntoDatabase: " + account
1764 + ", skipping since the account already exists");
1765 return false;
1766 }
1767 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1768 if (accountId < 0) {
1769 Log.w(TAG, "insertAccountIntoDatabase: " + account
1770 + ", skipping the DB insert failed");
1771 return false;
1772 }
1773 // Insert into DE table
1774 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1775 Log.w(TAG, "insertAccountIntoDatabase: " + account
1776 + ", skipping the DB insert failed");
1777 return false;
1778 }
1779 if (extras != null) {
1780 for (String key : extras.keySet()) {
1781 final String value = extras.getString(key);
1782 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1783 Log.w(TAG, "insertAccountIntoDatabase: " + account
1784 + ", skipping since insertExtra failed for key " + key);
1785 return false;
1786 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001787 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001788 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001789
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001790 if (packageToVisibility != null) {
1791 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1792 setAccountVisibility(account, entry.getKey() /* package */,
1793 entry.getValue() /* visibility */, false /* notify */,
1794 accounts);
1795 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001796 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001797 accounts.accountsDb.setTransactionSuccessful();
1798
1799 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1800 accountId,
1801 accounts, callingUid);
1802
1803 insertAccountIntoCacheLocked(accounts, account);
1804 } finally {
1805 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001806 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001807 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001808 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001809 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1810 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001811 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001812
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001813 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001814 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1815 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001816
Amith Yamasani5be347b2013-03-31 17:44:31 -07001817 return true;
1818 }
1819
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001820 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001821 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001822 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001823 }
1824 }
1825
Amith Yamasani5be347b2013-03-31 17:44:31 -07001826 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001827 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001828 * running, then clone the account too.
1829 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001830 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001831 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001832 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001833 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001834 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001835 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001836 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001837 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001838 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001839 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001840 }
1841 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001842 }
1843 }
1844
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001845 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001846 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001847 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001848 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001849 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001850 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1851 Log.v(TAG, "hasFeatures: " + account
1852 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001853 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001854 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001855 + ", pid " + Binder.getCallingPid());
1856 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001857 Preconditions.checkArgument(account != null, "account cannot be null");
1858 Preconditions.checkArgument(response != null, "response cannot be null");
1859 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001860 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001861 checkReadAccountsPermitted(callingUid, account.type, userId,
1862 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001863
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001864 long identityToken = clearCallingIdentity();
1865 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001866 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001867 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001868 } finally {
1869 restoreCallingIdentity(identityToken);
1870 }
1871 }
1872
1873 private class TestFeaturesSession extends Session {
1874 private final String[] mFeatures;
1875 private final Account mAccount;
1876
Amith Yamasani04e0d262012-02-14 11:50:53 -08001877 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001878 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001879 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001880 true /* stripAuthTokenFromResult */, account.name,
1881 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001882 mFeatures = features;
1883 mAccount = account;
1884 }
1885
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001886 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001887 public void run() throws RemoteException {
1888 try {
1889 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1890 } catch (RemoteException e) {
1891 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1892 }
1893 }
1894
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001895 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001896 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001897 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001898 IAccountManagerResponse response = getResponseAndClose();
1899 if (response != null) {
1900 try {
1901 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001902 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001903 return;
1904 }
Fred Quintana56285a62010-12-02 14:20:51 -08001905 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1906 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1907 + response);
1908 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001909 final Bundle newResult = new Bundle();
1910 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1911 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1912 response.onResult(newResult);
1913 } catch (RemoteException e) {
1914 // if the caller is dead then there is no one to care about remote exceptions
1915 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1916 Log.v(TAG, "failure while notifying response", e);
1917 }
1918 }
1919 }
1920 }
1921
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001922 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001923 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001924 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001925 + ", " + mAccount
1926 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1927 }
1928 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001929
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001930 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001931 public void renameAccount(
1932 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001933 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001934 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1935 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001936 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001937 + ", pid " + Binder.getCallingPid());
1938 }
1939 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001940 int userId = UserHandle.getCallingUserId();
1941 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001942 String msg = String.format(
1943 "uid %s cannot rename accounts of type: %s",
1944 callingUid,
1945 accountToRename.type);
1946 throw new SecurityException(msg);
1947 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001948 long identityToken = clearCallingIdentity();
1949 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001950 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001951 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001952 Bundle result = new Bundle();
1953 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1954 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001955 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1956 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001957 try {
1958 response.onResult(result);
1959 } catch (RemoteException e) {
1960 Log.w(TAG, e.getMessage());
1961 }
1962 } finally {
1963 restoreCallingIdentity(identityToken);
1964 }
1965 }
1966
1967 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001968 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001969 Account resultAccount = null;
1970 /*
1971 * Cancel existing notifications. Let authenticators
1972 * re-post notifications as required. But we don't know if
1973 * the authenticators have bound their notifications to
1974 * now stale account name data.
1975 *
1976 * With a rename api, we might not need to do this anymore but it
1977 * shouldn't hurt.
1978 */
1979 cancelNotification(
1980 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04001981 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001982 synchronized(accounts.credentialsPermissionNotificationIds) {
1983 for (Pair<Pair<Account, String>, Integer> pair:
1984 accounts.credentialsPermissionNotificationIds.keySet()) {
1985 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04001986 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001987 cancelNotification(id, new UserHandle(accounts.userId));
1988 }
1989 }
1990 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001991 synchronized (accounts.dbLock) {
1992 synchronized (accounts.cacheLock) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001993 List<String> accountRemovedReceivers =
1994 getAccountRemovedReceivers(accountToRename, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001995 accounts.accountsDb.beginTransaction();
1996 Account renamedAccount = new Account(newName, accountToRename.type);
1997 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1998 Log.e(TAG, "renameAccount failed - account with new name already exists");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001999 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002000 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002001 try {
2002 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2003 if (accountId >= 0) {
2004 accounts.accountsDb.renameCeAccount(accountId, newName);
2005 if (accounts.accountsDb.renameDeAccount(
2006 accountId, newName, accountToRename.name)) {
2007 accounts.accountsDb.setTransactionSuccessful();
2008 } else {
2009 Log.e(TAG, "renameAccount failed");
2010 return null;
2011 }
2012 } else {
2013 Log.e(TAG, "renameAccount failed - old account does not exist");
2014 return null;
2015 }
2016 } finally {
2017 accounts.accountsDb.endTransaction();
2018 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002019 /*
2020 * Database transaction was successful. Clean up cached
2021 * data associated with the account in the user profile.
2022 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002023 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002024 /*
2025 * Extract the data and token caches before removing the
2026 * old account to preserve the user data associated with
2027 * the account.
2028 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002029 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2030 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2031 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2032 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002033 /*
2034 * Update the cached data associated with the renamed
2035 * account.
2036 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002037 accounts.userDataCache.put(renamedAccount, tmpData);
2038 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2039 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2040 accounts.previousNameCache.put(
2041 renamedAccount,
2042 new AtomicReference<>(accountToRename.name));
2043 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002044
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002045 int parentUserId = accounts.userId;
2046 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002047 /*
2048 * Owner or system user account was renamed, rename the account for
2049 * those users with which the account was shared.
2050 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002051 List<UserInfo> users = getUserManager().getUsers(true);
2052 for (UserInfo user : users) {
2053 if (user.isRestricted()
2054 && (user.restrictedProfileParentId == parentUserId)) {
2055 renameSharedAccountAsUser(accountToRename, newName, user.id);
2056 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002057 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002058 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002059
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002060 sendNotificationAccountUpdated(resultAccount, accounts);
2061 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002062 for (String packageName : accountRemovedReceivers) {
2063 sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2064 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002065 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002066 }
2067 return resultAccount;
2068 }
2069
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002070 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002071 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002072 return userInfo != null && userInfo.canHaveProfile();
2073 }
2074
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002075 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002076 public void removeAccount(IAccountManagerResponse response, Account account,
2077 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002078 removeAccountAsUser(
2079 response,
2080 account,
2081 expectActivityLaunch,
2082 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002083 }
2084
2085 @Override
2086 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002087 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002088 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002089 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2090 Log.v(TAG, "removeAccount: " + account
2091 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002092 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002093 + ", pid " + Binder.getCallingPid()
2094 + ", for user id " + userId);
2095 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002096 Preconditions.checkArgument(account != null, "account cannot be null");
2097 Preconditions.checkArgument(response != null, "response cannot be null");
2098
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002099 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002100 if (isCrossUser(callingUid, userId)) {
2101 throw new SecurityException(
2102 String.format(
2103 "User %s tying remove account for %s" ,
2104 UserHandle.getCallingUserId(),
2105 userId));
2106 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002107 /*
2108 * Only the system or authenticator should be allowed to remove accounts for that
2109 * authenticator. This will let users remove accounts (via Settings in the system) but not
2110 * arbitrary applications (like competing authenticators).
2111 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002112 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002113 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
2114 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002115 String msg = String.format(
2116 "uid %s cannot remove accounts of type: %s",
2117 callingUid,
2118 account.type);
2119 throw new SecurityException(msg);
2120 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002121 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002122 try {
2123 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2124 "User cannot modify accounts");
2125 } catch (RemoteException re) {
2126 }
2127 return;
2128 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002129 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002130 try {
2131 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2132 "User cannot modify accounts of this type (policy).");
2133 } catch (RemoteException re) {
2134 }
2135 return;
2136 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002137 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002138 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002139 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002140 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002141 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002142 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002143 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002144 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002145 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002146 }
2147 }
2148 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002149 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002150 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002151 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2152 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002153 accountId,
2154 accounts,
2155 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002156 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002157 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2158 } finally {
2159 restoreCallingIdentity(identityToken);
2160 }
2161 }
2162
2163 @Override
2164 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002165 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002166 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2167 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002168 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002169 + ", pid " + Binder.getCallingPid());
2170 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002171 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002172 if (account == null) {
2173 /*
2174 * Null accounts should result in returning false, as per
2175 * AccountManage.addAccountExplicitly(...) java doc.
2176 */
2177 Log.e(TAG, "account is null");
2178 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002179 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002180 String msg = String.format(
2181 "uid %s cannot explicitly add accounts of type: %s",
2182 callingUid,
2183 account.type);
2184 throw new SecurityException(msg);
2185 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002186 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002187 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002188 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002189 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2190 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002191 accountId,
2192 accounts,
2193 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002194 long identityToken = clearCallingIdentity();
2195 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002196 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002197 } finally {
2198 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002199 }
Fred Quintana60307342009-03-24 22:48:12 -07002200 }
2201
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002202 private class RemoveAccountSession extends Session {
2203 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002204 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002205 Account account, boolean expectActivityLaunch) {
2206 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002207 true /* stripAuthTokenFromResult */, account.name,
2208 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002209 mAccount = account;
2210 }
2211
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002212 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002213 protected String toDebugString(long now) {
2214 return super.toDebugString(now) + ", removeAccount"
2215 + ", account " + mAccount;
2216 }
2217
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002218 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002219 public void run() throws RemoteException {
2220 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2221 }
2222
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002223 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002224 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002225 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002226 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2227 && !result.containsKey(AccountManager.KEY_INTENT)) {
2228 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002229 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002230 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002231 }
2232 IAccountManagerResponse response = getResponseAndClose();
2233 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002234 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2235 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2236 + response);
2237 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002238 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002239 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002240 try {
2241 response.onResult(result2);
2242 } catch (RemoteException e) {
2243 // ignore
2244 }
2245 }
2246 }
2247 super.onResult(result);
2248 }
2249 }
2250
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002251 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002252 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002253 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002254 }
2255
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002256 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002257 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002258 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002259 if (!userUnlocked) {
2260 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2261 + " is still locked. CE data will be removed later");
2262 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002263 synchronized (accounts.dbLock) {
2264 synchronized (accounts.cacheLock) {
2265 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2266 accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002267 List<String> accountRemovedReceivers =
2268 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002269 accounts.accountsDb.beginTransaction();
2270 // Set to a dummy value, this will only be used if the database
2271 // transaction succeeds.
2272 long accountId = -1;
2273 try {
2274 accountId = accounts.accountsDb.findDeAccountId(account);
2275 if (accountId >= 0) {
2276 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002277 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002278 // always delete from CE table if CE storage is available
2279 // DE account could be removed while CE was locked
2280 if (userUnlocked) {
2281 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2282 if (ceAccountId >= 0) {
2283 accounts.accountsDb.deleteCeAccount(ceAccountId);
2284 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002285 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002286 accounts.accountsDb.setTransactionSuccessful();
2287 } finally {
2288 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002289 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002290 if (isChanged) {
2291 removeAccountFromCacheLocked(accounts, account);
2292 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2293 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002294 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2295 || (packageToVisibility.getValue()
2296 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002297 notifyPackage(packageToVisibility.getKey(), accounts);
2298 }
2299 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002300
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002301 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2302 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002303 for (String packageName : accountRemovedReceivers) {
2304 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2305 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002306 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2307 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2308 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2309 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002310 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002311 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002312 long id = Binder.clearCallingIdentity();
2313 try {
2314 int parentUserId = accounts.userId;
2315 if (canHaveProfile(parentUserId)) {
2316 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002317 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002318 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002319 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002320 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002321 }
2322 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002323 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002324 } finally {
2325 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002326 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002327
2328 if (isChanged) {
2329 synchronized (accounts.credentialsPermissionNotificationIds) {
2330 for (Pair<Pair<Account, String>, Integer> key
2331 : accounts.credentialsPermissionNotificationIds.keySet()) {
2332 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002333 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002334 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002335 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002336 account, uid, false));
2337 }
2338 }
2339 }
2340 }
2341
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002342 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002343 }
2344
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002345 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002346 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002347 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002348 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2349 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002350 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2351 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002352 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002353 + ", pid " + Binder.getCallingPid());
2354 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002355 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002356 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002357 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002358 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002359 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002360 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002361 accounts.accountsDb.beginTransaction();
2362 try {
2363 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2364 accounts.accountsDb.setTransactionSuccessful();
2365 } finally {
2366 accounts.accountsDb.endTransaction();
2367 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002368 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002369 for (Pair<Account, String> tokenInfo : deletedTokens) {
2370 Account act = tokenInfo.first;
2371 String tokenType = tokenInfo.second;
2372 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002373 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002374 // wipe out cached token in memory.
2375 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002376 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002377 }
Fred Quintana60307342009-03-24 22:48:12 -07002378 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002379 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002380 }
2381 }
2382
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002383 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002384 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002385 // TODO Move to AccountsDB
2386 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002387 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002388
Fred Quintana33269202009-04-20 16:05:10 -07002389 try {
2390 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002391 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002392 String accountName = cursor.getString(1);
2393 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002394 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002395 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002396 }
Fred Quintana33269202009-04-20 16:05:10 -07002397 } finally {
2398 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002399 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002400 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002401 }
2402
Carlos Valdivia91979be2015-05-22 14:11:35 -07002403 private void saveCachedToken(
2404 UserAccounts accounts,
2405 Account account,
2406 String callerPkg,
2407 byte[] callerSigDigest,
2408 String tokenType,
2409 String token,
2410 long expiryMillis) {
2411
2412 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2413 return;
2414 }
2415 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002416 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002417 synchronized (accounts.cacheLock) {
2418 accounts.accountTokenCaches.put(
2419 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002420 }
2421 }
2422
Amith Yamasani04e0d262012-02-14 11:50:53 -08002423 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2424 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002425 if (account == null || type == null) {
2426 return false;
2427 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002428 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002429 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002430 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002431 accounts.accountsDb.beginTransaction();
2432 boolean updateCache = false;
2433 try {
2434 long accountId = accounts.accountsDb.findDeAccountId(account);
2435 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002436 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002437 }
2438 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2439 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2440 accounts.accountsDb.setTransactionSuccessful();
2441 updateCache = true;
2442 return true;
2443 }
2444 return false;
2445 } finally {
2446 accounts.accountsDb.endTransaction();
2447 if (updateCache) {
2448 synchronized (accounts.cacheLock) {
2449 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2450 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002451 }
Fred Quintana33269202009-04-20 16:05:10 -07002452 }
Fred Quintana60307342009-03-24 22:48:12 -07002453 }
2454 }
2455
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002456 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002457 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002458 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002459 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2460 Log.v(TAG, "peekAuthToken: " + account
2461 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002462 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002463 + ", pid " + Binder.getCallingPid());
2464 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002465 Preconditions.checkNotNull(account, "account cannot be null");
2466 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002467 int userId = UserHandle.getCallingUserId();
2468 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002469 String msg = String.format(
2470 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2471 callingUid,
2472 account.type);
2473 throw new SecurityException(msg);
2474 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002475 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002476 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2477 + callingUid);
2478 return null;
2479 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002480 long identityToken = clearCallingIdentity();
2481 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002482 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002483 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002484 } finally {
2485 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002486 }
Fred Quintana60307342009-03-24 22:48:12 -07002487 }
2488
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002489 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002490 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002491 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002492 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2493 Log.v(TAG, "setAuthToken: " + account
2494 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002495 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002496 + ", pid " + Binder.getCallingPid());
2497 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002498 Preconditions.checkNotNull(account, "account cannot be null");
2499 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002500 int userId = UserHandle.getCallingUserId();
2501 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002502 String msg = String.format(
2503 "uid %s cannot set auth tokens associated with accounts of type: %s",
2504 callingUid,
2505 account.type);
2506 throw new SecurityException(msg);
2507 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002508 long identityToken = clearCallingIdentity();
2509 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002510 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002511 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002512 } finally {
2513 restoreCallingIdentity(identityToken);
2514 }
Fred Quintana60307342009-03-24 22:48:12 -07002515 }
2516
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002517 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002518 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002519 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002520 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2521 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002522 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002523 + ", pid " + Binder.getCallingPid());
2524 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002525 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002526 int userId = UserHandle.getCallingUserId();
2527 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002528 String msg = String.format(
2529 "uid %s cannot set secrets for accounts of type: %s",
2530 callingUid,
2531 account.type);
2532 throw new SecurityException(msg);
2533 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002534 long identityToken = clearCallingIdentity();
2535 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002536 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002537 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002538 } finally {
2539 restoreCallingIdentity(identityToken);
2540 }
Fred Quintana60307342009-03-24 22:48:12 -07002541 }
2542
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002543 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2544 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002545 if (account == null) {
2546 return;
2547 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002548 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002549 synchronized (accounts.dbLock) {
2550 synchronized (accounts.cacheLock) {
2551 accounts.accountsDb.beginTransaction();
2552 try {
2553 final long accountId = accounts.accountsDb.findDeAccountId(account);
2554 if (accountId >= 0) {
2555 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2556 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2557 accounts.authTokenCache.remove(account);
2558 accounts.accountTokenCaches.remove(account);
2559 accounts.accountsDb.setTransactionSuccessful();
2560 // If there is an account whose password will be updated and the database
2561 // transactions succeed, then we say that a change has occured. Even if the
2562 // new password is the same as the old and there were no authtokens to
2563 // delete.
2564 isChanged = true;
2565 String action = (password == null || password.length() == 0) ?
2566 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2567 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2568 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2569 callingUid);
2570 }
2571 } finally {
2572 accounts.accountsDb.endTransaction();
2573 if (isChanged) {
2574 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2575 sendNotificationAccountUpdated(account, accounts);
2576 sendAccountsChangedBroadcast(accounts.userId);
2577 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002578 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002579 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002580 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002581 }
2582
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002583 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002584 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002585 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002586 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2587 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002588 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002589 + ", pid " + Binder.getCallingPid());
2590 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002591 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002592 int userId = UserHandle.getCallingUserId();
2593 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002594 String msg = String.format(
2595 "uid %s cannot clear passwords for accounts of type: %s",
2596 callingUid,
2597 account.type);
2598 throw new SecurityException(msg);
2599 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002600 long identityToken = clearCallingIdentity();
2601 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002602 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002603 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002604 } finally {
2605 restoreCallingIdentity(identityToken);
2606 }
Fred Quintana60307342009-03-24 22:48:12 -07002607 }
2608
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002609 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002610 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002611 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002612 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2613 Log.v(TAG, "setUserData: " + account
2614 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002615 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002616 + ", pid " + Binder.getCallingPid());
2617 }
Fred Quintana382601f2010-03-25 12:25:10 -07002618 if (key == null) throw new IllegalArgumentException("key is null");
2619 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002620 int userId = UserHandle.getCallingUserId();
2621 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002622 String msg = String.format(
2623 "uid %s cannot set user data for accounts of type: %s",
2624 callingUid,
2625 account.type);
2626 throw new SecurityException(msg);
2627 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002628 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002629 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002630 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002631 if (!accountExistsCache(accounts, account)) {
2632 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002633 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002634 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002635 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002636 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002637 }
2638 }
2639
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002640 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2641 synchronized (accounts.cacheLock) {
2642 if (accounts.accountCache.containsKey(account.type)) {
2643 for (Account acc : accounts.accountCache.get(account.type)) {
2644 if (acc.name.equals(account.name)) {
2645 return true;
2646 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002647 }
2648 }
2649 }
2650 return false;
2651 }
2652
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002653 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002654 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002655 synchronized (accounts.dbLock) {
2656 accounts.accountsDb.beginTransaction();
2657 try {
2658 long accountId = accounts.accountsDb.findDeAccountId(account);
2659 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002660 return;
2661 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002662 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2663 if (extrasId < 0) {
2664 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2665 if (extrasId < 0) {
2666 return;
2667 }
2668 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2669 return;
2670 }
2671 accounts.accountsDb.setTransactionSuccessful();
2672 } finally {
2673 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002674 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002675 synchronized (accounts.cacheLock) {
2676 writeUserDataIntoCacheLocked(accounts, account, key, value);
2677 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002678 }
2679 }
2680
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002681 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002682 if (result == null) {
2683 Log.e(TAG, "the result is unexpectedly null", new Exception());
2684 }
2685 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2686 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2687 + response);
2688 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002689 try {
2690 response.onResult(result);
2691 } catch (RemoteException e) {
2692 // if the caller is dead then there is no one to care about remote
2693 // exceptions
2694 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2695 Log.v(TAG, "failure while notifying response", e);
2696 }
2697 }
2698 }
2699
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002700 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002701 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2702 final String authTokenType)
2703 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002704 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2705 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002706
Fred Quintanad9640ec2012-05-23 12:37:00 -07002707 final int callingUid = getCallingUid();
2708 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002709 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002710 throw new SecurityException("can only call from system");
2711 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002712 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002713 long identityToken = clearCallingIdentity();
2714 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002715 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002716 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2717 false /* stripAuthTokenFromResult */, null /* accountName */,
2718 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002719 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002720 protected String toDebugString(long now) {
2721 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002722 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002723 + ", authTokenType " + authTokenType;
2724 }
2725
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002726 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002727 public void run() throws RemoteException {
2728 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2729 }
2730
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002731 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002732 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002733 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002734 if (result != null) {
2735 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2736 Bundle bundle = new Bundle();
2737 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2738 super.onResult(bundle);
2739 return;
2740 } else {
2741 super.onResult(result);
2742 }
2743 }
2744 }.bind();
2745 } finally {
2746 restoreCallingIdentity(identityToken);
2747 }
2748 }
2749
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002750 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002751 public void getAuthToken(
2752 IAccountManagerResponse response,
2753 final Account account,
2754 final String authTokenType,
2755 final boolean notifyOnAuthFailure,
2756 final boolean expectActivityLaunch,
2757 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002758 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002759 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2760 Log.v(TAG, "getAuthToken: " + account
2761 + ", response " + response
2762 + ", authTokenType " + authTokenType
2763 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2764 + ", expectActivityLaunch " + expectActivityLaunch
2765 + ", caller's uid " + Binder.getCallingUid()
2766 + ", pid " + Binder.getCallingPid());
2767 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002768 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002769 try {
2770 if (account == null) {
2771 Slog.w(TAG, "getAuthToken called with null account");
2772 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2773 return;
2774 }
2775 if (authTokenType == null) {
2776 Slog.w(TAG, "getAuthToken called with null authTokenType");
2777 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2778 return;
2779 }
2780 } catch (RemoteException e) {
2781 Slog.w(TAG, "Failed to report error back to the client." + e);
2782 return;
2783 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002784 int userId = UserHandle.getCallingUserId();
2785 long ident = Binder.clearCallingIdentity();
2786 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002787 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002788 try {
2789 accounts = getUserAccounts(userId);
2790 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2791 AuthenticatorDescription.newKey(account.type), accounts.userId);
2792 } finally {
2793 Binder.restoreCallingIdentity(ident);
2794 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002795
Costin Manolachea40c6302010-12-13 14:50:45 -08002796 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002797 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002798
2799 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002800 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002801 final boolean permissionGranted =
2802 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002803
Carlos Valdivia91979be2015-05-22 14:11:35 -07002804 // Get the calling package. We will use it for the purpose of caching.
2805 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002806 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002807 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002808 try {
2809 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2810 } finally {
2811 Binder.restoreCallingIdentity(ident);
2812 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002813 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2814 String msg = String.format(
2815 "Uid %s is attempting to illegally masquerade as package %s!",
2816 callerUid,
2817 callerPkg);
2818 throw new SecurityException(msg);
2819 }
2820
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002821 // let authenticator know the identity of the caller
2822 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2823 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002824
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002825 if (notifyOnAuthFailure) {
2826 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002827 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002828
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002829 long identityToken = clearCallingIdentity();
2830 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002831 // Distill the caller's package signatures into a single digest.
2832 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2833
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002834 // if the caller has permission, do the peek. otherwise go the more expensive
2835 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002836 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002837 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002838 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002839 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002840 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2841 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2842 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002843 onResult(response, result);
2844 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002845 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002846 }
2847
Carlos Valdivia91979be2015-05-22 14:11:35 -07002848 if (customTokens) {
2849 /*
2850 * Look up tokens in the new cache only if the loginOptions don't have parameters
2851 * outside of those expected to be injected by the AccountManager, e.g.
2852 * ANDORID_PACKAGE_NAME.
2853 */
2854 String token = readCachedTokenInternal(
2855 accounts,
2856 account,
2857 authTokenType,
2858 callerPkg,
2859 callerPkgSigDigest);
2860 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002861 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2862 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2863 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002864 Bundle result = new Bundle();
2865 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2866 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2867 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2868 onResult(response, result);
2869 return;
2870 }
2871 }
2872
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002873 new Session(
2874 accounts,
2875 response,
2876 account.type,
2877 expectActivityLaunch,
2878 false /* stripAuthTokenFromResult */,
2879 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002880 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002881 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002882 protected String toDebugString(long now) {
2883 if (loginOptions != null) loginOptions.keySet();
2884 return super.toDebugString(now) + ", getAuthToken"
2885 + ", " + account
2886 + ", authTokenType " + authTokenType
2887 + ", loginOptions " + loginOptions
2888 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2889 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002890
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002891 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002892 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002893 // If the caller doesn't have permission then create and return the
2894 // "grant permission" intent instead of the "getAuthToken" intent.
2895 if (!permissionGranted) {
2896 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2897 } else {
2898 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2899 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002900 }
2901
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002902 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002903 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002904 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002905 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002906 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002907 Intent intent = newGrantCredentialsPermissionIntent(
2908 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002909 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002910 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002911 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002912 authTokenType,
2913 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002914 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002915 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002916 onResult(bundle);
2917 return;
2918 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002919 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002920 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002921 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2922 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002923 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002924 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002925 "the type and name should not be empty");
2926 return;
2927 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002928 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002929 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002930 saveAuthTokenToDatabase(
2931 mAccounts,
2932 resultAccount,
2933 authTokenType,
2934 authToken);
2935 }
2936 long expiryMillis = result.getLong(
2937 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2938 if (customTokens
2939 && expiryMillis > System.currentTimeMillis()) {
2940 saveCachedToken(
2941 mAccounts,
2942 account,
2943 callerPkg,
2944 callerPkgSigDigest,
2945 authTokenType,
2946 authToken,
2947 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002948 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002949 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002950
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002951 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002952 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002953 /*
2954 * Make sure that the supplied intent is owned by the authenticator
2955 * giving it to the system. Otherwise a malicious authenticator could
2956 * have users launching arbitrary activities by tricking users to
2957 * interact with malicious notifications.
2958 */
2959 checkKeyIntent(
2960 Binder.getCallingUid(),
2961 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002962 doNotification(
2963 mAccounts,
2964 account,
2965 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002966 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002967 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002968 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002969 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002970 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002971 }.bind();
2972 } finally {
2973 restoreCallingIdentity(identityToken);
2974 }
Fred Quintana60307342009-03-24 22:48:12 -07002975 }
2976
Carlos Valdivia91979be2015-05-22 14:11:35 -07002977 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2978 MessageDigest digester;
2979 try {
2980 digester = MessageDigest.getInstance("SHA-256");
2981 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2982 callerPkg, PackageManager.GET_SIGNATURES);
2983 for (Signature sig : pkgInfo.signatures) {
2984 digester.update(sig.toByteArray());
2985 }
2986 } catch (NoSuchAlgorithmException x) {
2987 Log.wtf(TAG, "SHA-256 should be available", x);
2988 digester = null;
2989 } catch (NameNotFoundException e) {
2990 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2991 digester = null;
2992 }
2993 return (digester == null) ? null : digester.digest();
2994 }
2995
Dianne Hackborn41203752012-08-31 14:05:51 -07002996 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002997 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002998 int uid = intent.getIntExtra(
2999 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3000 String authTokenType = intent.getStringExtra(
3001 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07003002 final String titleAndSubtitle =
3003 mContext.getString(R.string.permission_request_notification_with_subtitle,
3004 account.name);
3005 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07003006 String title = titleAndSubtitle;
3007 String subtitle = "";
3008 if (index > 0) {
3009 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04003010 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07003011 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07003012 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003013 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003014 Notification n =
3015 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3016 .setSmallIcon(android.R.drawable.stat_sys_warning)
3017 .setWhen(0)
3018 .setColor(contextForUser.getColor(
3019 com.android.internal.R.color.system_notification_accent_color))
3020 .setContentTitle(title)
3021 .setContentText(subtitle)
3022 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3023 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
3024 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003025 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003026 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003027 }
3028
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003029 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3030 int uid, AccountAuthenticatorResponse response, String authTokenType,
3031 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003032
3033 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003034
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003035 if (startInNewTask) {
3036 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3037 // Since it was set in Eclair+ we can't change it without breaking apps using
3038 // the intent from a non-Activity context. This is the default behavior.
3039 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3040 }
Chris Wren717a8812017-03-31 15:34:39 -04003041 intent.addCategory(getCredentialPermissionNotificationId(account,
3042 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003043 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003044 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3045 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003046 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003047
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003048 return intent;
3049 }
3050
Chris Wren717a8812017-03-31 15:34:39 -04003051 private NotificationId getCredentialPermissionNotificationId(Account account,
3052 String authTokenType, int uid) {
3053 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003054 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003055 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003056 final Pair<Pair<Account, String>, Integer> key =
3057 new Pair<Pair<Account, String>, Integer>(
3058 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04003059 nId = accounts.credentialsPermissionNotificationIds.get(key);
3060 if (nId == null) {
3061 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3062 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
3063 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3064 nId = new NotificationId(tag, id);
3065 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003066 }
3067 }
Chris Wren717a8812017-03-31 15:34:39 -04003068 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003069 }
3070
Chris Wren717a8812017-03-31 15:34:39 -04003071 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3072 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08003073 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04003074 nId = accounts.signinRequiredNotificationIds.get(account);
3075 if (nId == null) {
3076 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3077 + ":" + account.hashCode();
3078 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3079 nId = new NotificationId(tag, id);
3080 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003081 }
3082 }
Chris Wren717a8812017-03-31 15:34:39 -04003083 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003084 }
3085
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003086 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07003087 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003088 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003089 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003090 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003091 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3092 Log.v(TAG, "addAccount: accountType " + accountType
3093 + ", response " + response
3094 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003095 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003096 + ", expectActivityLaunch " + expectActivityLaunch
3097 + ", caller's uid " + Binder.getCallingUid()
3098 + ", pid " + Binder.getCallingPid());
3099 }
Fred Quintana382601f2010-03-25 12:25:10 -07003100 if (response == null) throw new IllegalArgumentException("response is null");
3101 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003102
Amith Yamasani71e6c692013-03-24 17:39:28 -07003103 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003104 final int uid = Binder.getCallingUid();
3105 final int userId = UserHandle.getUserId(uid);
3106 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003107 try {
3108 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3109 "User is not allowed to add an account!");
3110 } catch (RemoteException re) {
3111 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003112 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003113 return;
3114 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003115 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003116 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003117 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3118 "User cannot modify accounts of this type (policy).");
3119 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003120 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003121 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3122 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003123 return;
3124 }
3125
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003126 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003127 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3128 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3129 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3130
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003131 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003132 long identityToken = clearCallingIdentity();
3133 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003134 UserAccounts accounts = getUserAccounts(usrId);
3135 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003136 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3137 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003138 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003139 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003140 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003141 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003142 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003143 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003144 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003145 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003146
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003147 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003148 protected String toDebugString(long now) {
3149 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003150 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003151 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003152 }
3153 }.bind();
3154 } finally {
3155 restoreCallingIdentity(identityToken);
3156 }
Fred Quintana60307342009-03-24 22:48:12 -07003157 }
3158
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003159 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003160 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3161 final String authTokenType, final String[] requiredFeatures,
3162 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003163 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003164 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003165 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3166 Log.v(TAG, "addAccount: accountType " + accountType
3167 + ", response " + response
3168 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003169 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003170 + ", expectActivityLaunch " + expectActivityLaunch
3171 + ", caller's uid " + Binder.getCallingUid()
3172 + ", pid " + Binder.getCallingPid()
3173 + ", for user id " + userId);
3174 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003175 Preconditions.checkArgument(response != null, "response cannot be null");
3176 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003177 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003178 if (isCrossUser(callingUid, userId)) {
3179 throw new SecurityException(
3180 String.format(
3181 "User %s trying to add account for %s" ,
3182 UserHandle.getCallingUserId(),
3183 userId));
3184 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003185
3186 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003187 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003188 try {
3189 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3190 "User is not allowed to add an account!");
3191 } catch (RemoteException re) {
3192 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003193 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003194 return;
3195 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003196 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003197 try {
3198 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3199 "User cannot modify accounts of this type (policy).");
3200 } catch (RemoteException re) {
3201 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003202 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3203 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003204 return;
3205 }
3206
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003207 final int pid = Binder.getCallingPid();
3208 final int uid = Binder.getCallingUid();
3209 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3210 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3211 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3212
3213 long identityToken = clearCallingIdentity();
3214 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003215 UserAccounts accounts = getUserAccounts(userId);
3216 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003217 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3218 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003219 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003220 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003221 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003222 @Override
3223 public void run() throws RemoteException {
3224 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3225 options);
3226 }
3227
3228 @Override
3229 protected String toDebugString(long now) {
3230 return super.toDebugString(now) + ", addAccount"
3231 + ", accountType " + accountType
3232 + ", requiredFeatures "
3233 + (requiredFeatures != null
3234 ? TextUtils.join(",", requiredFeatures)
3235 : null);
3236 }
3237 }.bind();
3238 } finally {
3239 restoreCallingIdentity(identityToken);
3240 }
3241 }
3242
Sandra Kwan78812282015-11-04 11:19:47 -08003243 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003244 public void startAddAccountSession(
3245 final IAccountManagerResponse response,
3246 final String accountType,
3247 final String authTokenType,
3248 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003249 final boolean expectActivityLaunch,
3250 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003251 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003252 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3253 Log.v(TAG,
3254 "startAddAccountSession: accountType " + accountType
3255 + ", response " + response
3256 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003257 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003258 + ", expectActivityLaunch " + expectActivityLaunch
3259 + ", caller's uid " + Binder.getCallingUid()
3260 + ", pid " + Binder.getCallingPid());
3261 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003262 Preconditions.checkArgument(response != null, "response cannot be null");
3263 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003264
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003265 final int uid = Binder.getCallingUid();
3266 final int userId = UserHandle.getUserId(uid);
3267 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003268 try {
3269 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3270 "User is not allowed to add an account!");
3271 } catch (RemoteException re) {
3272 }
3273 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3274 return;
3275 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003276 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003277 try {
3278 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3279 "User cannot modify accounts of this type (policy).");
3280 } catch (RemoteException re) {
3281 }
3282 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3283 userId);
3284 return;
3285 }
Sandra Kwan78812282015-11-04 11:19:47 -08003286 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003287 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3288 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3289 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3290
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003291 // Check to see if the Password should be included to the caller.
3292 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3293 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003294 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003295
Sandra Kwan78812282015-11-04 11:19:47 -08003296 long identityToken = clearCallingIdentity();
3297 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003298 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003299 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3300 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003301 new StartAccountSession(
3302 accounts,
3303 response,
3304 accountType,
3305 expectActivityLaunch,
3306 null /* accountName */,
3307 false /* authDetailsRequired */,
3308 true /* updateLastAuthenticationTime */,
3309 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003310 @Override
3311 public void run() throws RemoteException {
3312 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3313 requiredFeatures, options);
3314 }
3315
3316 @Override
3317 protected String toDebugString(long now) {
3318 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3319 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3320 + accountType + ", requiredFeatures "
3321 + (requiredFeatures != null ? requiredFeaturesStr : null);
3322 }
3323 }.bind();
3324 } finally {
3325 restoreCallingIdentity(identityToken);
3326 }
3327 }
3328
3329 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3330 private abstract class StartAccountSession extends Session {
3331
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003332 private final boolean mIsPasswordForwardingAllowed;
3333
3334 public StartAccountSession(
3335 UserAccounts accounts,
3336 IAccountManagerResponse response,
3337 String accountType,
3338 boolean expectActivityLaunch,
3339 String accountName,
3340 boolean authDetailsRequired,
3341 boolean updateLastAuthenticationTime,
3342 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003343 super(accounts, response, accountType, expectActivityLaunch,
3344 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3345 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003346 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003347 }
3348
3349 @Override
3350 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003351 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003352 mNumResults++;
3353 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003354 if (result != null
3355 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003356 checkKeyIntent(
3357 Binder.getCallingUid(),
3358 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003359 }
Sandra Kwan78812282015-11-04 11:19:47 -08003360 IAccountManagerResponse response;
3361 if (mExpectActivityLaunch && result != null
3362 && result.containsKey(AccountManager.KEY_INTENT)) {
3363 response = mResponse;
3364 } else {
3365 response = getResponseAndClose();
3366 }
3367 if (response == null) {
3368 return;
3369 }
3370 if (result == null) {
3371 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3372 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3373 + response);
3374 }
3375 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3376 "null bundle returned");
3377 return;
3378 }
3379
3380 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3381 // All AccountManager error codes are greater
3382 // than 0
3383 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3384 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3385 return;
3386 }
3387
Hongming Jin368aa192016-07-29 14:29:54 -07003388 // Omit passwords if the caller isn't permitted to see them.
3389 if (!mIsPasswordForwardingAllowed) {
3390 result.remove(AccountManager.KEY_PASSWORD);
3391 }
3392
Sandra Kwan78812282015-11-04 11:19:47 -08003393 // Strip auth token from result.
3394 result.remove(AccountManager.KEY_AUTHTOKEN);
3395
3396 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3397 Log.v(TAG,
3398 getClass().getSimpleName() + " calling onResult() on response " + response);
3399 }
3400
3401 // Get the session bundle created by authenticator. The
3402 // bundle contains data necessary for finishing the session
3403 // later. The session bundle will be encrypted here and
3404 // decrypted later when trying to finish the session.
3405 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3406 if (sessionBundle != null) {
3407 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3408 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003409 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003410 Log.w(TAG, "Account type in session bundle doesn't match request.");
3411 }
3412 // Add accountType info to session bundle. This will
3413 // override any value set by authenticator.
3414 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3415
3416 // Encrypt session bundle before returning to caller.
3417 try {
3418 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3419 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3420 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3421 } catch (GeneralSecurityException e) {
3422 if (Log.isLoggable(TAG, Log.DEBUG)) {
3423 Log.v(TAG, "Failed to encrypt session bundle!", e);
3424 }
3425 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3426 "failed to encrypt session bundle");
3427 return;
3428 }
3429 }
3430
3431 sendResponse(response, result);
3432 }
3433 }
3434
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003435 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003436 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003437 @NonNull Bundle sessionBundle,
3438 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003439 Bundle appInfo,
3440 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003441 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003442 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003443 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3444 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003445 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003446 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003447 + ", caller's uid " + callingUid
3448 + ", caller's user id " + UserHandle.getCallingUserId()
3449 + ", pid " + Binder.getCallingPid()
3450 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003451 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003452 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003453 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3454 // Account type is added to it before encryption.
3455 if (sessionBundle == null || sessionBundle.size() == 0) {
3456 throw new IllegalArgumentException("sessionBundle is empty");
3457 }
3458
Dmitry Dementyev52745472016-12-02 10:27:45 -08003459 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003460 if (isCrossUser(callingUid, userId)) {
3461 throw new SecurityException(
3462 String.format(
3463 "User %s trying to finish session for %s without cross user permission",
3464 UserHandle.getCallingUserId(),
3465 userId));
3466 }
3467
Sandra Kwan0b84b452016-01-20 15:25:42 -08003468 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003469 sendErrorResponse(response,
3470 AccountManager.ERROR_CODE_USER_RESTRICTED,
3471 "User is not allowed to add an account!");
3472 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3473 return;
3474 }
3475
3476 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003477 final Bundle decryptedBundle;
3478 final String accountType;
3479 // First decrypt session bundle to get account type for checking permission.
3480 try {
3481 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3482 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3483 if (decryptedBundle == null) {
3484 sendErrorResponse(
3485 response,
3486 AccountManager.ERROR_CODE_BAD_REQUEST,
3487 "failed to decrypt session bundle");
3488 return;
3489 }
3490 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3491 // Account type cannot be null. This should not happen if session bundle was created
3492 // properly by #StartAccountSession.
3493 if (TextUtils.isEmpty(accountType)) {
3494 sendErrorResponse(
3495 response,
3496 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3497 "accountType is empty");
3498 return;
3499 }
3500
3501 // If by any chances, decryptedBundle contains colliding keys with
3502 // system info
3503 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3504 // update credentials flow, we should replace with the new values of the current call.
3505 if (appInfo != null) {
3506 decryptedBundle.putAll(appInfo);
3507 }
3508
3509 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003510 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003511 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3512 } catch (GeneralSecurityException e) {
3513 if (Log.isLoggable(TAG, Log.DEBUG)) {
3514 Log.v(TAG, "Failed to decrypt session bundle!", e);
3515 }
3516 sendErrorResponse(
3517 response,
3518 AccountManager.ERROR_CODE_BAD_REQUEST,
3519 "failed to decrypt session bundle");
3520 return;
3521 }
3522
Sandra Kwan0b84b452016-01-20 15:25:42 -08003523 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003524 sendErrorResponse(
3525 response,
3526 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3527 "User cannot modify accounts of this type (policy).");
3528 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3529 userId);
3530 return;
3531 }
3532
3533 long identityToken = clearCallingIdentity();
3534 try {
3535 UserAccounts accounts = getUserAccounts(userId);
3536 logRecordWithUid(
3537 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003538 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3539 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003540 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003541 new Session(
3542 accounts,
3543 response,
3544 accountType,
3545 expectActivityLaunch,
3546 true /* stripAuthTokenFromResult */,
3547 null /* accountName */,
3548 false /* authDetailsRequired */,
3549 true /* updateLastAuthenticationTime */) {
3550 @Override
3551 public void run() throws RemoteException {
3552 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3553 }
3554
3555 @Override
3556 protected String toDebugString(long now) {
3557 return super.toDebugString(now)
3558 + ", finishSession"
3559 + ", accountType " + accountType;
3560 }
3561 }.bind();
3562 } finally {
3563 restoreCallingIdentity(identityToken);
3564 }
3565 }
3566
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003567 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003568 final DevicePolicyManagerInternal dpmi =
3569 LocalServices.getService(DevicePolicyManagerInternal.class);
3570 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003571 if (dpmi == null) {
3572 intent = getDefaultCantAddAccountIntent(errorCode);
3573 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003574 intent = dpmi.createUserRestrictionSupportIntent(userId,
3575 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3576 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3577 intent = dpmi.createShowAdminSupportIntent(userId, false);
3578 }
3579 if (intent == null) {
3580 intent = getDefaultCantAddAccountIntent(errorCode);
3581 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003582 long identityToken = clearCallingIdentity();
3583 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003584 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003585 } finally {
3586 restoreCallingIdentity(identityToken);
3587 }
3588 }
3589
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003590 /**
3591 * Called when we don't know precisely who is preventing us from adding an account.
3592 */
3593 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3594 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3595 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3596 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3597 return cantAddAccount;
3598 }
3599
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003600 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003601 public void confirmCredentialsAsUser(
3602 IAccountManagerResponse response,
3603 final Account account,
3604 final Bundle options,
3605 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003606 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003607 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003608 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003609 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3610 Log.v(TAG, "confirmCredentials: " + account
3611 + ", response " + response
3612 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003613 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003614 + ", pid " + Binder.getCallingPid());
3615 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003616 // Only allow the system process to read accounts of other users
3617 if (isCrossUser(callingUid, userId)) {
3618 throw new SecurityException(
3619 String.format(
3620 "User %s trying to confirm account credentials for %s" ,
3621 UserHandle.getCallingUserId(),
3622 userId));
3623 }
Fred Quintana382601f2010-03-25 12:25:10 -07003624 if (response == null) throw new IllegalArgumentException("response is null");
3625 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003626 long identityToken = clearCallingIdentity();
3627 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003628 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003629 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003630 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003631 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003632 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003633 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003634 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003635 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003636 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003637 protected String toDebugString(long now) {
3638 return super.toDebugString(now) + ", confirmCredentials"
3639 + ", " + account;
3640 }
3641 }.bind();
3642 } finally {
3643 restoreCallingIdentity(identityToken);
3644 }
Fred Quintana60307342009-03-24 22:48:12 -07003645 }
3646
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003647 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003648 public void updateCredentials(IAccountManagerResponse response, final Account account,
3649 final String authTokenType, final boolean expectActivityLaunch,
3650 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003651 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003652 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3653 Log.v(TAG, "updateCredentials: " + account
3654 + ", response " + response
3655 + ", authTokenType " + authTokenType
3656 + ", expectActivityLaunch " + expectActivityLaunch
3657 + ", caller's uid " + Binder.getCallingUid()
3658 + ", pid " + Binder.getCallingPid());
3659 }
Fred Quintana382601f2010-03-25 12:25:10 -07003660 if (response == null) throw new IllegalArgumentException("response is null");
3661 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003662 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003663 long identityToken = clearCallingIdentity();
3664 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003665 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003666 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003667 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003668 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003669 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003670 public void run() throws RemoteException {
3671 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3672 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003673 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003674 protected String toDebugString(long now) {
3675 if (loginOptions != null) loginOptions.keySet();
3676 return super.toDebugString(now) + ", updateCredentials"
3677 + ", " + account
3678 + ", authTokenType " + authTokenType
3679 + ", loginOptions " + loginOptions;
3680 }
3681 }.bind();
3682 } finally {
3683 restoreCallingIdentity(identityToken);
3684 }
Fred Quintana60307342009-03-24 22:48:12 -07003685 }
3686
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003687 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003688 public void startUpdateCredentialsSession(
3689 IAccountManagerResponse response,
3690 final Account account,
3691 final String authTokenType,
3692 final boolean expectActivityLaunch,
3693 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003694 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003695 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3696 Log.v(TAG,
3697 "startUpdateCredentialsSession: " + account + ", response " + response
3698 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3699 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3700 + ", pid " + Binder.getCallingPid());
3701 }
3702 if (response == null) {
3703 throw new IllegalArgumentException("response is null");
3704 }
3705 if (account == null) {
3706 throw new IllegalArgumentException("account is null");
3707 }
Sandra Kwana578d112015-12-16 16:01:43 -08003708
3709 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003710 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003711
3712 // Check to see if the Password should be included to the caller.
3713 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3714 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003715 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003716
Sandra Kwane68c37e2015-11-12 17:11:49 -08003717 long identityToken = clearCallingIdentity();
3718 try {
3719 UserAccounts accounts = getUserAccounts(userId);
3720 new StartAccountSession(
3721 accounts,
3722 response,
3723 account.type,
3724 expectActivityLaunch,
3725 account.name,
3726 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003727 true /* updateLastCredentialTime */,
3728 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003729 @Override
3730 public void run() throws RemoteException {
3731 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3732 loginOptions);
3733 }
3734
3735 @Override
3736 protected String toDebugString(long now) {
3737 if (loginOptions != null)
3738 loginOptions.keySet();
3739 return super.toDebugString(now)
3740 + ", startUpdateCredentialsSession"
3741 + ", " + account
3742 + ", authTokenType " + authTokenType
3743 + ", loginOptions " + loginOptions;
3744 }
3745 }.bind();
3746 } finally {
3747 restoreCallingIdentity(identityToken);
3748 }
3749 }
3750
3751 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003752 public void isCredentialsUpdateSuggested(
3753 IAccountManagerResponse response,
3754 final Account account,
3755 final String statusToken) {
3756 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3757 Log.v(TAG,
3758 "isCredentialsUpdateSuggested: " + account + ", response " + response
3759 + ", caller's uid " + Binder.getCallingUid()
3760 + ", pid " + Binder.getCallingPid());
3761 }
3762 if (response == null) {
3763 throw new IllegalArgumentException("response is null");
3764 }
3765 if (account == null) {
3766 throw new IllegalArgumentException("account is null");
3767 }
3768 if (TextUtils.isEmpty(statusToken)) {
3769 throw new IllegalArgumentException("status token is empty");
3770 }
3771
Sandra Kwan390c9d22016-01-12 14:13:37 -08003772 int usrId = UserHandle.getCallingUserId();
3773 long identityToken = clearCallingIdentity();
3774 try {
3775 UserAccounts accounts = getUserAccounts(usrId);
3776 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3777 false /* stripAuthTokenFromResult */, account.name,
3778 false /* authDetailsRequired */) {
3779 @Override
3780 protected String toDebugString(long now) {
3781 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3782 + ", " + account;
3783 }
3784
3785 @Override
3786 public void run() throws RemoteException {
3787 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3788 }
3789
3790 @Override
3791 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003792 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003793 IAccountManagerResponse response = getResponseAndClose();
3794 if (response == null) {
3795 return;
3796 }
3797
3798 if (result == null) {
3799 sendErrorResponse(
3800 response,
3801 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3802 "null bundle");
3803 return;
3804 }
3805
3806 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3807 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3808 + response);
3809 }
3810 // Check to see if an error occurred. We know if an error occurred because all
3811 // error codes are greater than 0.
3812 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3813 sendErrorResponse(response,
3814 result.getInt(AccountManager.KEY_ERROR_CODE),
3815 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3816 return;
3817 }
3818 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3819 sendErrorResponse(
3820 response,
3821 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3822 "no result in response");
3823 return;
3824 }
3825 final Bundle newResult = new Bundle();
3826 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3827 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3828 sendResponse(response, newResult);
3829 }
3830 }.bind();
3831 } finally {
3832 restoreCallingIdentity(identityToken);
3833 }
3834 }
3835
3836 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003837 public void editProperties(IAccountManagerResponse response, final String accountType,
3838 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003839 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003840 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3841 Log.v(TAG, "editProperties: accountType " + accountType
3842 + ", response " + response
3843 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003844 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003845 + ", pid " + Binder.getCallingPid());
3846 }
Fred Quintana382601f2010-03-25 12:25:10 -07003847 if (response == null) throw new IllegalArgumentException("response is null");
3848 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003849 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003850 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3851 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003852 String msg = String.format(
3853 "uid %s cannot edit authenticator properites for account type: %s",
3854 callingUid,
3855 accountType);
3856 throw new SecurityException(msg);
3857 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003858 long identityToken = clearCallingIdentity();
3859 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003860 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003861 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003862 true /* stripAuthTokenFromResult */, null /* accountName */,
3863 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003864 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003865 public void run() throws RemoteException {
3866 mAuthenticator.editProperties(this, mAccountType);
3867 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003868 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003869 protected String toDebugString(long now) {
3870 return super.toDebugString(now) + ", editProperties"
3871 + ", accountType " + accountType;
3872 }
3873 }.bind();
3874 } finally {
3875 restoreCallingIdentity(identityToken);
3876 }
Fred Quintana60307342009-03-24 22:48:12 -07003877 }
3878
Amith Yamasani12747872015-12-07 14:19:49 -08003879 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003880 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3881 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003882 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003883 throw new SecurityException("Can be called only by system UID");
3884 }
3885 Preconditions.checkNotNull(account, "account cannot be null");
3886 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3887 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3888
3889 final int userId = userHandle.getIdentifier();
3890
3891 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3892
3893 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003894 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003895 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003896 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003897 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003898 return false;
3899 }
3900 }
3901
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003902 // Returns package with oldest target SDK for given UID.
3903 private String getPackageNameForUid(int uid) {
3904 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3905 if (ArrayUtils.isEmpty(packageNames)) {
3906 return null;
3907 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003908 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003909 if (packageNames.length == 1) {
3910 return packageName;
3911 }
3912 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003913 int oldestVersion = Integer.MAX_VALUE;
3914 for (String name : packageNames) {
3915 try {
3916 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3917 if (applicationInfo != null) {
3918 int version = applicationInfo.targetSdkVersion;
3919 if (version < oldestVersion) {
3920 oldestVersion = version;
3921 packageName = name;
3922 }
3923 }
3924 } catch (NameNotFoundException e) {
3925 // skip
3926 }
3927 }
3928 return packageName;
3929 }
3930
Svet Ganovf6d424f12016-09-20 20:18:53 -07003931 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3932 int uid) {
3933 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003934 packageName = getPackageNameForUid(uid);
3935 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003936 return false;
3937 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003938 }
3939
3940 // Use null token which means any token. Having a token means the package
3941 // is trusted by the authenticator, hence it is fine to access the account.
3942 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3943 return true;
3944 }
3945 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003946 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003947
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003948 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003949 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003950 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003951 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003952 }
3953
3954 @Override
3955 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3956 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003957 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003958 throw new SecurityException("Can be called only by system UID");
3959 }
3960
3961 Preconditions.checkNotNull(account, "account cannot be null");
3962 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3963 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3964
3965 final int userId = userHandle.getIdentifier();
3966
3967 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3968
3969 final int uid;
3970 try {
3971 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3972 } catch (NameNotFoundException e) {
3973 Slog.e(TAG, "Unknown package " + packageName);
3974 return null;
3975 }
3976
3977 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3978
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003979 final long identity = Binder.clearCallingIdentity();
3980 try {
3981 return PendingIntent.getActivityAsUser(
3982 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3983 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3984 null, new UserHandle(userId)).getIntentSender();
3985 } finally {
3986 Binder.restoreCallingIdentity(identity);
3987 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003988 }
3989
3990 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3991 int uid, RemoteCallback callback) {
3992 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3993 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3994 @Override
3995 public void onResult(Bundle value) throws RemoteException {
3996 handleAuthenticatorResponse(true);
3997 }
3998
3999 @Override
4000 public void onRequestContinued() {
4001 /* ignore */
4002 }
4003
4004 @Override
4005 public void onError(int errorCode, String errorMessage) throws RemoteException {
4006 handleAuthenticatorResponse(false);
4007 }
4008
4009 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4010 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07004011 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004012 UserHandle.getUserHandleForUid(uid));
4013 if (callback != null) {
4014 Bundle result = new Bundle();
4015 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4016 callback.sendResult(result);
4017 }
4018 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07004019 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004020 }
4021
4022 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08004023 public boolean someUserHasAccount(@NonNull final Account account) {
4024 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4025 throw new SecurityException("Only system can check for accounts across users");
4026 }
4027 final long token = Binder.clearCallingIdentity();
4028 try {
4029 AccountAndUser[] allAccounts = getAllAccounts();
4030 for (int i = allAccounts.length - 1; i >= 0; i--) {
4031 if (allAccounts[i].account.equals(account)) {
4032 return true;
4033 }
4034 }
4035 return false;
4036 } finally {
4037 Binder.restoreCallingIdentity(token);
4038 }
4039 }
4040
Fred Quintana33269202009-04-20 16:05:10 -07004041 private class GetAccountsByTypeAndFeatureSession extends Session {
4042 private final String[] mFeatures;
4043 private volatile Account[] mAccountsOfType = null;
4044 private volatile ArrayList<Account> mAccountsWithFeatures = null;
4045 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004046 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004047 private final String mPackageName;
sunjianf29d5492017-05-11 15:42:31 -07004048 private final boolean mIncludeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004049
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004050 public GetAccountsByTypeAndFeatureSession(
4051 UserAccounts accounts,
4052 IAccountManagerResponse response,
4053 String type,
4054 String[] features,
4055 int callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004056 String packageName,
4057 boolean includeManagedNotVisible) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004058 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004059 true /* stripAuthTokenFromResult */, null /* accountName */,
4060 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004061 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07004062 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004063 mPackageName = packageName;
sunjianf29d5492017-05-11 15:42:31 -07004064 mIncludeManagedNotVisible = includeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004065 }
4066
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004067 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004068 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004069 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
sunjianf29d5492017-05-11 15:42:31 -07004070 mCallingUid, mPackageName, mIncludeManagedNotVisible);
Fred Quintana33269202009-04-20 16:05:10 -07004071 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07004072 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07004073 mCurrentAccount = 0;
4074
4075 checkAccount();
4076 }
4077
4078 public void checkAccount() {
4079 if (mCurrentAccount >= mAccountsOfType.length) {
4080 sendResult();
4081 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07004082 }
Fred Quintana33269202009-04-20 16:05:10 -07004083
Fred Quintana29e94b82010-03-10 12:11:51 -08004084 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4085 if (accountAuthenticator == null) {
4086 // It is possible that the authenticator has died, which is indicated by
4087 // mAuthenticator being set to null. If this happens then just abort.
4088 // There is no need to send back a result or error in this case since
4089 // that already happened when mAuthenticator was cleared.
4090 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4091 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4092 + " connected to the authenticator, " + toDebugString());
4093 }
4094 return;
4095 }
Fred Quintana33269202009-04-20 16:05:10 -07004096 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004097 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004098 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004099 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004100 }
4101 }
4102
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004103 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004104 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004105 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004106 mNumResults++;
4107 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004108 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004109 return;
4110 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004111 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004112 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4113 }
4114 mCurrentAccount++;
4115 checkAccount();
4116 }
4117
4118 public void sendResult() {
4119 IAccountManagerResponse response = getResponseAndClose();
4120 if (response != null) {
4121 try {
4122 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4123 for (int i = 0; i < accounts.length; i++) {
4124 accounts[i] = mAccountsWithFeatures.get(i);
4125 }
Fred Quintana56285a62010-12-02 14:20:51 -08004126 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4127 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4128 + response);
4129 }
Fred Quintana33269202009-04-20 16:05:10 -07004130 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004131 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004132 response.onResult(result);
4133 } catch (RemoteException e) {
4134 // if the caller is dead then there is no one to care about remote exceptions
4135 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4136 Log.v(TAG, "failure while notifying response", e);
4137 }
4138 }
4139 }
4140 }
4141
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004142 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004143 protected String toDebugString(long now) {
4144 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4145 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4146 }
4147 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004148
Amith Yamasani04e0d262012-02-14 11:50:53 -08004149 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004150 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004151 * @hide
4152 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004153 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004154 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004155 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004156 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004157 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4158 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004159 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004160 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004161 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004162 long identityToken = clearCallingIdentity();
4163 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004164 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004165 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004166 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004167 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004168 opPackageName,
4169 visibleAccountTypes,
4170 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004171 } finally {
4172 restoreCallingIdentity(identityToken);
4173 }
4174 }
4175
Amith Yamasanif29f2362012-04-05 18:29:52 -07004176 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004177 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004178 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004179 * @hide
4180 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004181 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004182 public AccountAndUser[] getRunningAccounts() {
4183 final int[] runningUserIds;
4184 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004185 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004186 } catch (RemoteException e) {
4187 // Running in system_server; should never happen
4188 throw new RuntimeException(e);
4189 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004190 return getAccounts(runningUserIds);
4191 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004192
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004193 /**
4194 * Returns accounts for all users, ignores visibility values.
4195 *
4196 * @hide
4197 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004198 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004199 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004200 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004201 final int[] userIds = new int[users.size()];
4202 for (int i = 0; i < userIds.length; i++) {
4203 userIds[i] = users.get(i).id;
4204 }
4205 return getAccounts(userIds);
4206 }
4207
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004208 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004209 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004210 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004211 for (int userId : userIds) {
4212 UserAccounts userAccounts = getUserAccounts(userId);
4213 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004214 Account[] accounts = getAccountsFromCache(
4215 userAccounts,
4216 null /* type */,
4217 Binder.getCallingUid(),
4218 null /* packageName */,
4219 false /* include managed not visible*/);
4220 for (Account account : accounts) {
4221 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004222 }
4223 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004224
4225 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4226 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004227 }
4228
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004229 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004230 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004231 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004232 int callingUid = Binder.getCallingUid();
4233 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004234 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004235 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004236 }
4237
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004238 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004239 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004240 String type,
4241 int userId,
4242 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004243 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004244 String opPackageName,
4245 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004246 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004247 // Only allow the system process to read accounts of other users
4248 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004249 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004250 && mContext.checkCallingOrSelfPermission(
4251 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4252 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004253 throw new SecurityException("User " + UserHandle.getCallingUserId()
4254 + " trying to get account for " + userId);
4255 }
4256
Fred Quintana56285a62010-12-02 14:20:51 -08004257 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4258 Log.v(TAG, "getAccounts: accountType " + type
4259 + ", caller's uid " + Binder.getCallingUid()
4260 + ", pid " + Binder.getCallingPid());
4261 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004262
4263 // If the original calling app was using account choosing activity
4264 // provided by the framework or authenticator we'll passing in
4265 // the original caller's uid here, which is what should be used for filtering.
4266 List<String> managedTypes =
4267 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4268 if (packageUid != -1 &&
4269 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4270 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004271 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004272 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004273 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004274 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4275 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004276 if (visibleAccountTypes.isEmpty()
4277 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004278 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004279 } else if (visibleAccountTypes.contains(type)) {
4280 // Prune the list down to just the requested type.
4281 visibleAccountTypes = new ArrayList<>();
4282 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004283 } // else aggregate all the visible accounts (it won't matter if the
4284 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004285
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004286 long identityToken = clearCallingIdentity();
4287 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004288 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004289 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004290 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004291 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004292 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004293 visibleAccountTypes,
4294 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004295 } finally {
4296 restoreCallingIdentity(identityToken);
4297 }
4298 }
4299
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004300 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004301 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004302 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004303 int callingUid,
4304 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004305 List<String> visibleAccountTypes,
4306 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004307 ArrayList<Account> visibleAccounts = new ArrayList<>();
4308 for (String visibleType : visibleAccountTypes) {
4309 Account[] accountsForType = getAccountsFromCache(
4310 userAccounts, visibleType, callingUid, callingPackage,
4311 includeUserManagedNotVisible);
4312 if (accountsForType != null) {
4313 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004314 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004315 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004316 Account[] result = new Account[visibleAccounts.size()];
4317 for (int i = 0; i < visibleAccounts.size(); i++) {
4318 result[i] = visibleAccounts.get(i);
4319 }
4320 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004321 }
4322
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004323 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004324 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4325 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004326 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004327 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004328 for (Account account : accounts) {
4329 addSharedAccountAsUser(account, userId);
4330 }
4331 }
4332
4333 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004334 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004335 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004336 accounts.accountsDb.deleteSharedAccount(account);
4337 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004338 if (accountId < 0) {
4339 Log.w(TAG, "insertAccountIntoDatabase: " + account
4340 + ", skipping the DB insert failed");
4341 return false;
4342 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004343 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4344 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004345 return true;
4346 }
4347
4348 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004349 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4350 userId = handleIncomingUser(userId);
4351 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004352 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4353 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004354 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004355 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004356 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004357 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004358 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004359 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004360 }
4361 return r > 0;
4362 }
4363
4364 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004365 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004366 return removeSharedAccountAsUser(account, userId, getCallingUid());
4367 }
4368
4369 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004370 userId = handleIncomingUser(userId);
4371 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004372 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4373 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004374 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004375 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004376 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004377 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004378 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004379 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004380 }
4381
4382 @Override
4383 public Account[] getSharedAccountsAsUser(int userId) {
4384 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004385 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004386 synchronized (accounts.dbLock) {
4387 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4388 Account[] accountArray = new Account[accountList.size()];
4389 accountList.toArray(accountArray);
4390 return accountArray;
4391 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004392 }
4393
4394 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004395 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004396 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004397 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004398 }
4399
Amith Yamasani27db4682013-03-30 17:07:47 -07004400 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004401 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004402 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004403 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004404 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004405 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004406 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4407 + callingUid + " with uid=" + uid);
4408 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004409 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004410 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004411 }
4412
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004413 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004414 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004415 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4416 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004417 int callingUid = Binder.getCallingUid();
4418 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004419 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004420 int packageUid = -1;
4421 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004422 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4423 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004424 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004425 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004426 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004427 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004428 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4429 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004430 }
sunjiand62dc392017-06-01 12:05:59 -07004431 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4432 return getAccountsAsUserForPackage(type, userId,
4433 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4434 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004435 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004436 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004437 }
4438
sunjianf29d5492017-05-11 15:42:31 -07004439 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4440 if (accounts.length < 1) return false;
4441 if (accounts.length > 1) return true;
4442 Account account = accounts[0];
4443 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4444 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4445 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4446 return false;
4447 }
4448
4449 private void startChooseAccountActivityWithAccounts(
4450 IAccountManagerResponse response, Account[] accounts) {
4451 Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4452 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4453 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4454 new AccountManagerResponse(response));
4455
4456 mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4457 }
4458
4459 private void handleGetAccountsResult(
4460 IAccountManagerResponse response,
4461 Account[] accounts,
4462 String callingPackage) {
4463
4464 if (needToStartChooseAccountActivity(accounts, callingPackage)) {
4465 startChooseAccountActivityWithAccounts(response, accounts);
4466 return;
4467 }
4468 if (accounts.length == 1) {
4469 Bundle bundle = new Bundle();
4470 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4471 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4472 onResult(response, bundle);
4473 return;
4474 }
4475 // No qualified account exists, return an empty Bundle.
4476 onResult(response, new Bundle());
4477 }
4478
4479 @Override
4480 public void getAccountByTypeAndFeatures(
4481 IAccountManagerResponse response,
4482 String accountType,
4483 String[] features,
4484 String opPackageName) {
4485
4486 int callingUid = Binder.getCallingUid();
4487 mAppOpsManager.checkPackage(callingUid, opPackageName);
4488 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4489 Log.v(TAG, "getAccount: accountType " + accountType
4490 + ", response " + response
4491 + ", features " + Arrays.toString(features)
4492 + ", caller's uid " + callingUid
4493 + ", pid " + Binder.getCallingPid());
4494 }
4495 if (response == null) throw new IllegalArgumentException("response is null");
4496 if (accountType == null) throw new IllegalArgumentException("accountType is null");
4497
4498 int userId = UserHandle.getCallingUserId();
4499
4500 long identityToken = clearCallingIdentity();
4501 try {
4502 UserAccounts userAccounts = getUserAccounts(userId);
4503 if (ArrayUtils.isEmpty(features)) {
4504 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4505 userAccounts, accountType, callingUid, opPackageName,
4506 true /* include managed not visible */);
4507 handleGetAccountsResult(
4508 response, accountsWithManagedNotVisible, opPackageName);
4509 return;
4510 }
4511
4512 IAccountManagerResponse retrieveAccountsResponse =
4513 new IAccountManagerResponse.Stub() {
4514 @Override
4515 public void onResult(Bundle value) throws RemoteException {
4516 Parcelable[] parcelables = value.getParcelableArray(
4517 AccountManager.KEY_ACCOUNTS);
4518 Account[] accounts = new Account[parcelables.length];
4519 for (int i = 0; i < parcelables.length; i++) {
4520 accounts[i] = (Account) parcelables[i];
4521 }
4522 handleGetAccountsResult(
4523 response, accounts, opPackageName);
4524 }
4525
4526 @Override
4527 public void onError(int errorCode, String errorMessage)
4528 throws RemoteException {
4529 // Will not be called in this case.
4530 }
4531 };
4532 new GetAccountsByTypeAndFeatureSession(
4533 userAccounts,
4534 retrieveAccountsResponse,
4535 accountType,
4536 features,
4537 callingUid,
4538 opPackageName,
4539 true /* include managed not visible */).bind();
4540 } finally {
4541 restoreCallingIdentity(identityToken);
4542 }
4543 }
4544
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004545 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004546 public void getAccountsByFeatures(
4547 IAccountManagerResponse response,
4548 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004549 String[] features,
4550 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004551 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004552 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004553 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4554 Log.v(TAG, "getAccounts: accountType " + type
4555 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004556 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004557 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004558 + ", pid " + Binder.getCallingPid());
4559 }
Fred Quintana382601f2010-03-25 12:25:10 -07004560 if (response == null) throw new IllegalArgumentException("response is null");
4561 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004562 int userId = UserHandle.getCallingUserId();
4563
Svetoslavf3f02ac2015-09-08 14:36:35 -07004564 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4565 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004566 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004567 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004568 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004569 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004570 try {
4571 response.onResult(result);
4572 } catch (RemoteException e) {
4573 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4574 }
4575 return;
4576 }
sunjianf29d5492017-05-11 15:42:31 -07004577
Fred Quintana33269202009-04-20 16:05:10 -07004578 long identityToken = clearCallingIdentity();
4579 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004580 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004581 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004582 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4583 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004584 Bundle result = new Bundle();
4585 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4586 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004587 return;
4588 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004589 new GetAccountsByTypeAndFeatureSession(
4590 userAccounts,
4591 response,
4592 type,
4593 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004594 callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004595 opPackageName,
4596 false /* include managed not visible */).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004597 } finally {
4598 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004599 }
4600 }
4601
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004602 @Override
4603 public void onAccountAccessed(String token) throws RemoteException {
4604 final int uid = Binder.getCallingUid();
4605 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4606 return;
4607 }
4608 final int userId = UserHandle.getCallingUserId();
4609 final long identity = Binder.clearCallingIdentity();
4610 try {
4611 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4612 if (Objects.equals(account.getAccessId(), token)) {
4613 // An app just accessed the account. At this point it knows about
4614 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004615 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004616 if (!hasAccountAccess(account, null, uid)) {
4617 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4618 uid, true);
4619 }
4620 }
4621 }
4622 } finally {
4623 Binder.restoreCallingIdentity(identity);
4624 }
4625 }
4626
Fred Quintanaa698f422009-04-08 19:14:54 -07004627 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004628 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004629 IAccountManagerResponse mResponse;
4630 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004631 final boolean mExpectActivityLaunch;
4632 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004633 final String mAccountName;
4634 // Indicates if we need to add auth details(like last credential time)
4635 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004636 // If set, we need to update the last authenticated time. This is
4637 // currently
4638 // used on
4639 // successful confirming credentials.
4640 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004641
Fred Quintana33269202009-04-20 16:05:10 -07004642 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004643 private int mNumRequestContinued = 0;
4644 private int mNumErrors = 0;
4645
Fred Quintana60307342009-03-24 22:48:12 -07004646 IAccountAuthenticator mAuthenticator = null;
4647
Fred Quintana8570f742010-02-18 10:32:54 -08004648 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004649 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004650
Amith Yamasani04e0d262012-02-14 11:50:53 -08004651 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004652 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4653 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004654 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4655 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4656 }
4657
4658 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4659 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4660 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004661 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004662 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004663 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004664 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004665 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004666 mResponse = response;
4667 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004668 mExpectActivityLaunch = expectActivityLaunch;
4669 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004670 mAccountName = accountName;
4671 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004672 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004673
Fred Quintanaa698f422009-04-08 19:14:54 -07004674 synchronized (mSessions) {
4675 mSessions.put(toString(), this);
4676 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004677 if (response != null) {
4678 try {
4679 response.asBinder().linkToDeath(this, 0 /* flags */);
4680 } catch (RemoteException e) {
4681 mResponse = null;
4682 binderDied();
4683 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004684 }
Fred Quintana60307342009-03-24 22:48:12 -07004685 }
4686
Fred Quintanaa698f422009-04-08 19:14:54 -07004687 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004688 if (mResponse == null) {
4689 // this session has already been closed
4690 return null;
4691 }
Fred Quintana60307342009-03-24 22:48:12 -07004692 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004693 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004694 return response;
4695 }
4696
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004697 /**
4698 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4699 * security policy.
4700 *
4701 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004702 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004703 * supplied entries in the system Settings app.
4704 */
4705 protected void checkKeyIntent(
4706 int authUid,
4707 Intent intent) throws SecurityException {
4708 long bid = Binder.clearCallingIdentity();
4709 try {
4710 PackageManager pm = mContext.getPackageManager();
4711 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4712 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4713 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004714 if (!isExportedSystemActivity(targetActivityInfo)
4715 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4716 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004717 String pkgName = targetActivityInfo.packageName;
4718 String activityName = targetActivityInfo.name;
4719 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4720 + "does not share a signature with the supplying authenticator (%s).";
4721 throw new SecurityException(
4722 String.format(tmpl, activityName, pkgName, mAccountType));
4723 }
4724 } finally {
4725 Binder.restoreCallingIdentity(bid);
4726 }
4727 }
4728
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004729 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4730 String className = activityInfo.name;
4731 return "android".equals(activityInfo.packageName) &&
4732 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4733 || CantAddAccountActivity.class.getName().equals(className));
4734 }
4735
Fred Quintanaa698f422009-04-08 19:14:54 -07004736 private void close() {
4737 synchronized (mSessions) {
4738 if (mSessions.remove(toString()) == null) {
4739 // the session was already closed, so bail out now
4740 return;
4741 }
4742 }
4743 if (mResponse != null) {
4744 // stop listening for response deaths
4745 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4746
4747 // clear this so that we don't accidentally send any further results
4748 mResponse = null;
4749 }
4750 cancelTimeout();
4751 unbind();
4752 }
4753
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004754 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004755 public void binderDied() {
4756 mResponse = null;
4757 close();
4758 }
4759
4760 protected String toDebugString() {
4761 return toDebugString(SystemClock.elapsedRealtime());
4762 }
4763
4764 protected String toDebugString(long now) {
4765 return "Session: expectLaunch " + mExpectActivityLaunch
4766 + ", connected " + (mAuthenticator != null)
4767 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4768 + "/" + mNumErrors + ")"
4769 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4770 }
4771
Fred Quintana60307342009-03-24 22:48:12 -07004772 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004773 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4774 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4775 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004776 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004777 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004778 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004779 }
4780 }
4781
4782 private void unbind() {
4783 if (mAuthenticator != null) {
4784 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004785 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004786 }
4787 }
4788
Fred Quintana60307342009-03-24 22:48:12 -07004789 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004790 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004791 }
4792
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004793 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004794 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004795 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004796 try {
4797 run();
4798 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004799 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004800 "remote exception");
4801 }
Fred Quintana60307342009-03-24 22:48:12 -07004802 }
4803
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004804 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004805 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004806 mAuthenticator = null;
4807 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004808 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004809 try {
4810 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4811 "disconnected");
4812 } catch (RemoteException e) {
4813 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4814 Log.v(TAG, "Session.onServiceDisconnected: "
4815 + "caught RemoteException while responding", e);
4816 }
4817 }
Fred Quintana60307342009-03-24 22:48:12 -07004818 }
4819 }
4820
Fred Quintanab839afc2009-10-14 15:57:28 -07004821 public abstract void run() throws RemoteException;
4822
Fred Quintana60307342009-03-24 22:48:12 -07004823 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004824 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004825 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004826 try {
4827 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4828 "timeout");
4829 } catch (RemoteException e) {
4830 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4831 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4832 e);
4833 }
4834 }
Fred Quintana60307342009-03-24 22:48:12 -07004835 }
4836 }
4837
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004838 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004839 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004840 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004841 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004842 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004843 if (result != null) {
4844 boolean isSuccessfulConfirmCreds = result.getBoolean(
4845 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004846 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004847 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4848 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004849 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004850 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4851 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004852 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004853 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004854 if (needUpdate || mAuthDetailsRequired) {
4855 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4856 if (needUpdate && accountPresent) {
4857 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4858 }
4859 if (mAuthDetailsRequired) {
4860 long lastAuthenticatedTime = -1;
4861 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004862 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004863 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004864 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004865 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004866 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004867 lastAuthenticatedTime);
4868 }
4869 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004870 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004871 if (result != null
4872 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004873 checkKeyIntent(
4874 Binder.getCallingUid(),
4875 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004876 }
4877 if (result != null
4878 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004879 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4880 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004881 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4882 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004883 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4884 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004885 }
Fred Quintana60307342009-03-24 22:48:12 -07004886 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004887 IAccountManagerResponse response;
4888 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004889 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004890 response = mResponse;
4891 } else {
4892 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004893 }
Fred Quintana60307342009-03-24 22:48:12 -07004894 if (response != null) {
4895 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004896 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004897 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4898 Log.v(TAG, getClass().getSimpleName()
4899 + " calling onError() on response " + response);
4900 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004901 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004902 "null bundle returned");
4903 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004904 if (mStripAuthTokenFromResult) {
4905 result.remove(AccountManager.KEY_AUTHTOKEN);
4906 }
Fred Quintana56285a62010-12-02 14:20:51 -08004907 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4908 Log.v(TAG, getClass().getSimpleName()
4909 + " calling onResult() on response " + response);
4910 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004911 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4912 (intent == null)) {
4913 // All AccountManager error codes are greater than 0
4914 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4915 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4916 } else {
4917 response.onResult(result);
4918 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004919 }
Fred Quintana60307342009-03-24 22:48:12 -07004920 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004921 // if the caller is dead then there is no one to care about remote exceptions
4922 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4923 Log.v(TAG, "failure while notifying response", e);
4924 }
Fred Quintana60307342009-03-24 22:48:12 -07004925 }
4926 }
4927 }
Fred Quintana60307342009-03-24 22:48:12 -07004928
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004929 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004930 public void onRequestContinued() {
4931 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004932 }
4933
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004934 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004935 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004936 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004937 IAccountManagerResponse response = getResponseAndClose();
4938 if (response != null) {
4939 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004940 Log.v(TAG, getClass().getSimpleName()
4941 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004942 }
4943 try {
4944 response.onError(errorCode, errorMessage);
4945 } catch (RemoteException e) {
4946 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4947 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4948 }
4949 }
4950 } else {
4951 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4952 Log.v(TAG, "Session.onError: already closed");
4953 }
Fred Quintana60307342009-03-24 22:48:12 -07004954 }
4955 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004956
4957 /**
4958 * find the component name for the authenticator and initiate a bind
4959 * if no authenticator or the bind fails then return false, otherwise return true
4960 */
4961 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004962 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4963 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4964 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004965 if (authenticatorInfo == null) {
4966 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4967 Log.v(TAG, "there is no authenticator for " + authenticatorType
4968 + ", bailing out");
4969 }
4970 return false;
4971 }
4972
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004973 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004974 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004975 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4976 + " which isn't encryption aware");
4977 return false;
4978 }
4979
Fred Quintanab839afc2009-10-14 15:57:28 -07004980 Intent intent = new Intent();
4981 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4982 intent.setComponent(authenticatorInfo.componentName);
4983 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4984 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4985 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004986 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004987 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004988 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4989 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4990 }
4991 return false;
4992 }
4993
Fred Quintanab839afc2009-10-14 15:57:28 -07004994 return true;
4995 }
Fred Quintana60307342009-03-24 22:48:12 -07004996 }
4997
Svet Ganov5d09c992016-09-07 09:57:41 -07004998 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004999 MessageHandler(Looper looper) {
5000 super(looper);
5001 }
Costin Manolache3348f142009-09-29 18:58:36 -07005002
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07005003 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005004 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07005005 switch (msg.what) {
5006 case MESSAGE_TIMED_OUT:
5007 Session session = (Session)msg.obj;
5008 session.onTimedOut();
5009 break;
5010
Amith Yamasani5be347b2013-03-31 17:44:31 -07005011 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00005012 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07005013 break;
5014
Fred Quintana60307342009-03-24 22:48:12 -07005015 default:
5016 throw new IllegalStateException("unhandled message: " + msg.what);
5017 }
5018 }
5019 }
5020
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005021 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005022 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005023 }
5024
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005025 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005026 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005027 }
5028
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005029 /*
5030 * This function receives an opened writable database.
5031 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005032 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005033 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005034 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005035 }
5036
5037 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005038 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005039 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005040 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005041 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005042
5043 class LogRecordTask implements Runnable {
5044 private final String action;
5045 private final String tableName;
5046 private final long accountId;
5047 private final UserAccounts userAccount;
5048 private final int callingUid;
5049 private final long userDebugDbInsertionPoint;
5050
5051 LogRecordTask(final String action,
5052 final String tableName,
5053 final long accountId,
5054 final UserAccounts userAccount,
5055 final int callingUid,
5056 final long userDebugDbInsertionPoint) {
5057 this.action = action;
5058 this.tableName = tableName;
5059 this.accountId = accountId;
5060 this.userAccount = userAccount;
5061 this.callingUid = callingUid;
5062 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5063 }
5064
5065 public void run() {
5066 SQLiteStatement logStatement = userAccount.statementForLogging;
5067 logStatement.bindLong(1, accountId);
5068 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005069 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005070 logStatement.bindLong(4, callingUid);
5071 logStatement.bindString(5, tableName);
5072 logStatement.bindLong(6, userDebugDbInsertionPoint);
5073 logStatement.execute();
5074 logStatement.clearBindings();
5075 }
5076 }
5077
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005078 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5079 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005080 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005081 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005082 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005083 }
5084
5085 /*
5086 * This should only be called once to compile the sql statement for logging
5087 * and to find the insertion point.
5088 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005089 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
5090 userAccount.debugDbInsertionPoint = userAccount.accountsDb
5091 .calculateDebugTableInsertionPoint();
5092 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005093 }
5094
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005095 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07005096 return asBinder();
5097 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005098
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005099 /**
5100 * Searches array of arguments for the specified string
5101 * @param args array of argument strings
5102 * @param value value to search for
5103 * @return true if the value is contained in the array
5104 */
5105 private static boolean scanArgs(String[] args, String value) {
5106 if (args != null) {
5107 for (String arg : args) {
5108 if (value.equals(arg)) {
5109 return true;
5110 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005111 }
5112 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005113 return false;
5114 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005115
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005116 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005117 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005118 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005119 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005120 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07005121
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005122 final List<UserInfo> users = getUserManager().getUsers();
5123 for (UserInfo user : users) {
5124 ipw.println("User " + user + ":");
5125 ipw.increaseIndent();
5126 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5127 ipw.println();
5128 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08005129 }
5130 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005131
Amith Yamasani04e0d262012-02-14 11:50:53 -08005132 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5133 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005134 if (isCheckinRequest) {
5135 // This is a checkin request. *Only* upload the account types and the count of
5136 // each.
5137 synchronized (userAccounts.dbLock) {
5138 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5139 }
5140 } else {
5141 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5142 Process.SYSTEM_UID, null /* packageName */, false);
5143 fout.println("Accounts: " + accounts.length);
5144 for (Account account : accounts) {
5145 fout.println(" " + account);
5146 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005147
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005148 // Add debug information.
5149 fout.println();
5150 synchronized (userAccounts.dbLock) {
5151 userAccounts.accountsDb.dumpDebugTable(fout);
5152 }
5153 fout.println();
5154 synchronized (mSessions) {
5155 final long now = SystemClock.elapsedRealtime();
5156 fout.println("Active Sessions: " + mSessions.size());
5157 for (Session session : mSessions.values()) {
5158 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005159 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005160 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005161
5162 fout.println();
5163 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005164 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005165 }
5166
Amith Yamasani04e0d262012-02-14 11:50:53 -08005167 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005168 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005169 long identityToken = clearCallingIdentity();
5170 try {
5171 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5172 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5173 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005174
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005175 if (intent.getComponent() != null &&
5176 GrantCredentialsPermissionActivity.class.getName().equals(
5177 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005178 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005179 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005180 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04005181 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5182 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005183
Fred Quintana33f889a2009-09-14 17:31:26 -07005184 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005185 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05005186 Notification n =
5187 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005188 .setWhen(0)
5189 .setSmallIcon(android.R.drawable.stat_sys_warning)
5190 .setColor(contextForUser.getColor(
5191 com.android.internal.R.color.system_notification_accent_color))
5192 .setContentTitle(String.format(notificationTitleFormat, account.name))
5193 .setContentText(message)
5194 .setContentIntent(PendingIntent.getActivityAsUser(
5195 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005196 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005197 .build();
Chris Wren717a8812017-03-31 15:34:39 -04005198 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005199 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005200 } finally {
5201 restoreCallingIdentity(identityToken);
5202 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005203 }
5204
Chris Wren717a8812017-03-31 15:34:39 -04005205 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005206 String packageName, int userId) {
5207 final long token = clearCallingIdentity();
5208 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005209 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005210 try {
Chris Wren717a8812017-03-31 15:34:39 -04005211 notificationManager.enqueueNotificationWithTag(packageName, packageName,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04005212 id.mTag, id.mId, notification, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005213 } catch (RemoteException e) {
5214 /* ignore - local call */
5215 }
5216 } finally {
5217 Binder.restoreCallingIdentity(token);
5218 }
Fred Quintana56285a62010-12-02 14:20:51 -08005219 }
5220
Chris Wren717a8812017-03-31 15:34:39 -04005221 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005222 cancelNotification(id, mContext.getPackageName(), user);
5223 }
5224
Chris Wren717a8812017-03-31 15:34:39 -04005225 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005226 long identityToken = clearCallingIdentity();
5227 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005228 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04005229 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005230 } catch (RemoteException e) {
5231 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005232 } finally {
5233 restoreCallingIdentity(identityToken);
5234 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005235 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005236
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005237 private boolean isPermittedForPackage(String packageName, int uid, int userId,
5238 String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005239 final long identity = Binder.clearCallingIdentity();
5240 try {
5241 IPackageManager pm = ActivityThread.getPackageManager();
5242 for (String perm : permissions) {
5243 if (pm.checkPermission(perm, packageName, userId)
5244 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005245 // Checks runtime permission revocation.
5246 final int opCode = AppOpsManager.permissionToOpCode(perm);
5247 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5248 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5249 return true;
5250 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005251 }
5252 }
5253 } catch (RemoteException e) {
5254 /* ignore - local call */
5255 } finally {
5256 Binder.restoreCallingIdentity(identity);
5257 }
5258 return false;
5259 }
5260
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005261 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5262 for (String perm : permissions) {
5263 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5264 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5265 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5266 }
5267 final int opCode = AppOpsManager.permissionToOpCode(perm);
5268 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5269 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5270 return true;
5271 }
5272 }
5273 }
5274 return false;
5275 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005276
Amith Yamasani67df64b2012-12-14 12:09:36 -08005277 private int handleIncomingUser(int userId) {
5278 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005279 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005280 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5281 } catch (RemoteException re) {
5282 // Shouldn't happen, local.
5283 }
5284 return userId;
5285 }
5286
Christopher Tateccbf84f2013-05-08 15:25:41 -07005287 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005288 String[] packages;
5289 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005290 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005291 packages = mPackageManager.getPackagesForUid(callingUid);
5292 } finally {
5293 Binder.restoreCallingIdentity(identityToken);
5294 }
5295 if (packages == null) {
5296 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005297 return false;
5298 }
Fred Quintana7be59642009-08-24 18:29:25 -07005299 for (String name : packages) {
5300 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005301 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08005302 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08005303 && (packageInfo.applicationInfo.privateFlags
5304 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07005305 return true;
5306 }
5307 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005308 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07005309 return false;
5310 }
5311 }
5312 return false;
5313 }
5314
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005315 private boolean permissionIsGranted(
5316 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005317 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5318 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5319 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5320 }
5321 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005322 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005323
5324 if (isPrivileged(callerUid)) {
5325 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5326 Log.v(TAG, "Access to " + account + " granted calling uid "
5327 + callerUid + " privileged");
5328 }
5329 return true;
5330 }
5331 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5332 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5333 Log.v(TAG, "Access to " + account + " granted calling uid "
5334 + callerUid + " manages the account");
5335 }
5336 return true;
5337 }
5338 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5339 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5340 Log.v(TAG, "Access to " + account + " granted calling uid "
5341 + callerUid + " user granted access");
5342 }
5343 return true;
5344 }
5345
5346 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5347 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5348 }
5349
5350 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005351 }
5352
Svetoslavf3f02ac2015-09-08 14:36:35 -07005353 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5354 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005355 if (accountType == null) {
5356 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005357 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005358 return getTypesVisibleToCaller(callingUid, userId,
5359 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005360 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005361 }
5362
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005363 // Method checks visibility for applications targeing API level below {@link
5364 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005365 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005366 private boolean checkGetAccountsPermission(String packageName, int uid, int userId) {
5367 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005368 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5369 }
5370
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005371 private boolean checkReadContactsPermission(String packageName, int uid, int userId) {
5372 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS);
5373 }
5374
5375 // Heuristic to check that account type may be associated with some contacts data and
5376 // therefore READ_CONTACTS permission grants the access to account by default.
5377 private boolean accountTypeManagesContacts(String accountType, int userId) {
5378 if (accountType == null) {
5379 return false;
5380 }
5381 long identityToken = Binder.clearCallingIdentity();
5382 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5383 try {
5384 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5385 } finally {
5386 Binder.restoreCallingIdentity(identityToken);
5387 }
5388 // Check contacts related permissions for authenticator.
5389 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5390 : serviceInfos) {
5391 if (accountType.equals(serviceInfo.type.type)) {
5392 return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId,
5393 Manifest.permission.WRITE_CONTACTS);
5394 }
5395 }
5396 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005397 }
5398
5399 /**
5400 * Method checks package uid and signature with Authenticator which manages accountType.
5401 *
5402 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5403 * SIGNATURE_CHECK_MISMATCH otherwise.
5404 */
5405 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5406 if (accountType == null) {
5407 return SIGNATURE_CHECK_MISMATCH;
5408 }
5409
5410 long identityToken = Binder.clearCallingIdentity();
5411 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5412 try {
5413 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5414 } finally {
5415 Binder.restoreCallingIdentity(identityToken);
5416 }
5417 // Check for signature match with Authenticator.
5418 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5419 : serviceInfos) {
5420 if (accountType.equals(serviceInfo.type.type)) {
5421 if (serviceInfo.uid == callingUid) {
5422 return SIGNATURE_CHECK_UID_MATCH;
5423 }
5424 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5425 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5426 return SIGNATURE_CHECK_MATCH;
5427 }
5428 }
5429 }
5430 return SIGNATURE_CHECK_MISMATCH;
5431 }
5432
5433 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005434 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5435 if (accountType == null) {
5436 return false;
5437 } else {
5438 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5439 }
5440 }
5441
Svetoslavf3f02ac2015-09-08 14:36:35 -07005442 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5443 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005444 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005445 }
5446
5447 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005448 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005449 }
5450
5451 private List<String> getTypesForCaller(
5452 int callingUid, int userId, boolean isOtherwisePermitted) {
5453 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005454 long identityToken = Binder.clearCallingIdentity();
5455 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5456 try {
5457 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5458 } finally {
5459 Binder.restoreCallingIdentity(identityToken);
5460 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005461 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005462 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005463 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5464 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005465 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005466 }
5467 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005468 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005469 }
5470
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005471 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5472 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5473 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5474 if (account.name.equals(accountName)) {
5475 return true;
5476 }
5477 }
5478 }
5479 return false;
5480 }
5481
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005482 private static void checkManageUsersPermission(String message) {
5483 if (ActivityManager.checkComponentPermission(
5484 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5485 != PackageManager.PERMISSION_GRANTED) {
5486 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5487 }
5488 }
5489
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005490 private static void checkManageOrCreateUsersPermission(String message) {
5491 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5492 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5493 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5494 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5495 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5496 + message);
5497 }
5498 }
5499
Amith Yamasani04e0d262012-02-14 11:50:53 -08005500 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5501 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005502 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005503 return true;
5504 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005505 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005506 synchronized (accounts.dbLock) {
5507 synchronized (accounts.cacheLock) {
5508 long grantsCount;
5509 if (authTokenType != null) {
5510 grantsCount = accounts.accountsDb
5511 .findMatchingGrantsCount(callerUid, authTokenType, account);
5512 } else {
5513 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5514 account);
5515 }
5516 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005517
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005518 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5519 // TODO: Skip this check when running automated tests. Replace this
5520 // with a more general solution.
5521 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5522 + authTokenType + " by uid " + callerUid
5523 + " but ignoring since device is in test harness.");
5524 return true;
5525 }
5526 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005527 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005528 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005529 }
5530
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005531 private boolean isSystemUid(int callingUid) {
5532 String[] packages = null;
5533 long ident = Binder.clearCallingIdentity();
5534 try {
5535 packages = mPackageManager.getPackagesForUid(callingUid);
5536 } finally {
5537 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005538 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005539 if (packages != null) {
5540 for (String name : packages) {
5541 try {
5542 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5543 if (packageInfo != null
5544 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5545 != 0) {
5546 return true;
5547 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005548 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005549 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5550 }
5551 }
5552 } else {
5553 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005554 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005555 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005556 }
5557
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005558 /** Succeeds if any of the specified permissions are granted. */
5559 private void checkReadAccountsPermitted(
5560 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005561 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005562 int userId,
5563 String opPackageName) {
5564 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005565 String msg = String.format(
5566 "caller uid %s cannot access %s accounts",
5567 callingUid,
5568 accountType);
5569 Log.w(TAG, " " + msg);
5570 throw new SecurityException(msg);
5571 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005572 }
5573
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005574 private boolean canUserModifyAccounts(int userId, int callingUid) {
5575 // the managing app can always modify accounts
5576 if (isProfileOwner(callingUid)) {
5577 return true;
5578 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005579 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5580 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5581 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005582 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005583 return true;
5584 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005585
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005586 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5587 // the managing app can always modify accounts
5588 if (isProfileOwner(callingUid)) {
5589 return true;
5590 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005591 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5592 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005593 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005594 if (typesArray == null) {
5595 return true;
5596 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005597 for (String forbiddenType : typesArray) {
5598 if (forbiddenType.equals(accountType)) {
5599 return false;
5600 }
5601 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005602 return true;
5603 }
5604
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005605 private boolean isProfileOwner(int uid) {
5606 final DevicePolicyManagerInternal dpmi =
5607 LocalServices.getService(DevicePolicyManagerInternal.class);
5608 return (dpmi != null)
5609 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5610 }
5611
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005612 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005613 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5614 throws RemoteException {
5615 final int callingUid = getCallingUid();
5616
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005617 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005618 throw new SecurityException();
5619 }
5620
5621 if (value) {
5622 grantAppPermission(account, authTokenType, uid);
5623 } else {
5624 revokeAppPermission(account, authTokenType, uid);
5625 }
5626 }
5627
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005628 /**
5629 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5630 * <p>
5631 * Although this is public it can only be accessed via the AccountManagerService object
5632 * which is in the system. This means we don't need to protect it with permissions.
5633 * @hide
5634 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005635 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005636 if (account == null || authTokenType == null) {
5637 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005638 return;
5639 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005640 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005641 synchronized (accounts.dbLock) {
5642 synchronized (accounts.cacheLock) {
5643 long accountId = accounts.accountsDb.findDeAccountId(account);
5644 if (accountId >= 0) {
5645 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5646 }
5647 cancelNotification(
5648 getCredentialPermissionNotificationId(account, authTokenType, uid),
5649 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005650
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005651 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5652 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005653 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005654
5655 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5656 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5657 : mAppPermissionChangeListeners) {
5658 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5659 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005660 }
5661
5662 /**
5663 * Don't allow callers with the given uid permission to get credentials for
5664 * account/authTokenType.
5665 * <p>
5666 * Although this is public it can only be accessed via the AccountManagerService object
5667 * which is in the system. This means we don't need to protect it with permissions.
5668 * @hide
5669 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005670 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005671 if (account == null || authTokenType == null) {
5672 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005673 return;
5674 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005675 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005676 synchronized (accounts.dbLock) {
5677 synchronized (accounts.cacheLock) {
5678 accounts.accountsDb.beginTransaction();
5679 try {
5680 long accountId = accounts.accountsDb.findDeAccountId(account);
5681 if (accountId >= 0) {
5682 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5683 accountId, authTokenType, uid);
5684 accounts.accountsDb.setTransactionSuccessful();
5685 }
5686 } finally {
5687 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005688 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005689
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005690 cancelNotification(
5691 getCredentialPermissionNotificationId(account, authTokenType, uid),
5692 UserHandle.of(accounts.userId));
5693 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005694 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005695
5696 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5697 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5698 : mAppPermissionChangeListeners) {
5699 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5700 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005701 }
Fred Quintana56285a62010-12-02 14:20:51 -08005702
Amith Yamasani04e0d262012-02-14 11:50:53 -08005703 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5704 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005705 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005706 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005707 for (Account curAccount : oldAccountsForType) {
5708 if (!curAccount.equals(account)) {
5709 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005710 }
5711 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005712 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005713 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005714 } else {
5715 Account[] newAccountsForType = new Account[newAccountsList.size()];
5716 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005717 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005718 }
Fred Quintana56285a62010-12-02 14:20:51 -08005719 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005720 accounts.userDataCache.remove(account);
5721 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005722 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005723 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005724 }
5725
5726 /**
5727 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005728 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5729 * processes and if you will return this account to apps you should return the result.
5730 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005731 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005732 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005733 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005734 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5735 Account[] newAccountsForType = new Account[oldLength + 1];
5736 if (accountsForType != null) {
5737 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005738 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005739 String token = account.getAccessId() != null ? account.getAccessId()
5740 : UUID.randomUUID().toString();
5741 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005742 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005743 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005744 }
5745
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005746 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005747 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005748 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005749 String visibilityFilterPackage = callingPackage;
5750 if (visibilityFilterPackage == null) {
5751 visibilityFilterPackage = getPackageNameForUid(callingUid);
5752 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005753 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005754 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005755 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005756 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5757 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5758 || (includeManagedNotVisible
5759 && (visibility
5760 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5761 firstPass.put(account, visibility);
5762 }
5763 }
5764 Map<Account, Integer> secondPass =
5765 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5766
5767 Account[] filtered = new Account[secondPass.size()];
5768 filtered = secondPass.keySet().toArray(filtered);
5769 return filtered;
5770 }
5771
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005772 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005773 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005774 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005775 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005776 // first part is to filter shared accounts.
5777 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005778 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005779 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005780 return unfiltered;
5781 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005782 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005783 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005784 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005785 if (packages == null) {
5786 packages = new String[] {};
5787 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005788 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005789 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005790 // This might be a temporary way to specify a visible list
5791 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005792 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5793 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005794 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005795 return unfiltered;
5796 }
5797 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005798 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005799 if (ArrayUtils.isEmpty(sharedAccounts)) {
5800 return unfiltered;
5801 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005802 String requiredAccountType = "";
5803 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005804 // If there's an explicit callingPackage specified, check if that package
5805 // opted in to see restricted accounts.
5806 if (callingPackage != null) {
5807 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005808 if (pi != null && pi.restrictedAccountType != null) {
5809 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005810 }
5811 } else {
5812 // Otherwise check if the callingUid has a package that has opted in
5813 for (String packageName : packages) {
5814 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5815 if (pi != null && pi.restrictedAccountType != null) {
5816 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005817 break;
5818 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005819 }
5820 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005821 } catch (NameNotFoundException e) {
5822 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005823 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005824 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005825 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5826 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005827 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005828 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005829 } else {
5830 boolean found = false;
5831 for (Account shared : sharedAccounts) {
5832 if (shared.equals(account)) {
5833 found = true;
5834 break;
5835 }
5836 }
5837 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005838 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005839 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005840 }
5841 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005842 return filtered;
5843 } else {
5844 return unfiltered;
5845 }
5846 }
5847
Amith Yamasani27db4682013-03-30 17:07:47 -07005848 /*
5849 * packageName can be null. If not null, it should be used to filter out restricted accounts
5850 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005851 *
5852 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5853 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005854 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005855 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005856 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005857 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005858 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5859 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005860 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005861 Account[] accounts;
5862 synchronized (userAccounts.cacheLock) {
5863 accounts = userAccounts.accountCache.get(accountType);
5864 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005865 if (accounts == null) {
5866 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005867 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005868 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5869 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005870 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005871 } else {
5872 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005873 Account[] accountsArray;
5874 synchronized (userAccounts.cacheLock) {
5875 for (Account[] accounts : userAccounts.accountCache.values()) {
5876 totalLength += accounts.length;
5877 }
5878 if (totalLength == 0) {
5879 return EMPTY_ACCOUNT_ARRAY;
5880 }
5881 accountsArray = new Account[totalLength];
5882 totalLength = 0;
5883 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5884 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5885 accountsOfType.length);
5886 totalLength += accountsOfType.length;
5887 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005888 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005889 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005890 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005891 }
5892 }
5893
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005894 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005895 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005896 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005897 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005898 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005899 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005900 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005901 }
5902 if (value == null) {
5903 userDataForAccount.remove(key);
5904 } else {
5905 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005906 }
5907 }
5908
Carlos Valdivia91979be2015-05-22 14:11:35 -07005909 protected String readCachedTokenInternal(
5910 UserAccounts accounts,
5911 Account account,
5912 String tokenType,
5913 String callingPackage,
5914 byte[] pkgSigDigest) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005915 synchronized (accounts.dbLock) {
5916 synchronized (accounts.cacheLock) {
5917 return accounts.accountTokenCaches.get(
5918 account, tokenType, callingPackage, pkgSigDigest);
5919 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07005920 }
5921 }
5922
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005923 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005924 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005925 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005926 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005927 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005928 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005929 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005930 }
5931 if (value == null) {
5932 authTokensForAccount.remove(key);
5933 } else {
5934 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005935 }
5936 }
5937
Amith Yamasani04e0d262012-02-14 11:50:53 -08005938 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5939 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005940 // Fast path - check if account is already cached
5941 synchronized (accounts.cacheLock) {
5942 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5943 if (authTokensForAccount != null) {
5944 return authTokensForAccount.get(authTokenType);
5945 }
5946 }
5947 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005948 synchronized (accounts.dbLock) {
5949 synchronized (accounts.cacheLock) {
5950 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5951 if (authTokensForAccount == null) {
5952 // need to populate the cache for this account
5953 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
5954 accounts.authTokenCache.put(account, authTokensForAccount);
5955 }
5956 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08005957 }
Fred Quintana56285a62010-12-02 14:20:51 -08005958 }
5959 }
5960
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005961 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
5962 Map<String, String> userDataForAccount;
5963 // Fast path - check if data is already cached
5964 synchronized (accounts.cacheLock) {
5965 userDataForAccount = accounts.userDataCache.get(account);
5966 }
5967 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00005968 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005969 synchronized (accounts.dbLock) {
5970 synchronized (accounts.cacheLock) {
5971 userDataForAccount = accounts.userDataCache.get(account);
5972 if (userDataForAccount == null) {
5973 // need to populate the cache for this account
5974 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
5975 accounts.userDataCache.put(account, userDataForAccount);
5976 }
5977 }
5978 }
Fred Quintana56285a62010-12-02 14:20:51 -08005979 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005980 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005981 }
5982
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005983 private Context getContextForUser(UserHandle user) {
5984 try {
5985 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5986 } catch (NameNotFoundException e) {
5987 // Default to mContext, not finding the package system is running as is unlikely.
5988 return mContext;
5989 }
5990 }
Sandra Kwan78812282015-11-04 11:19:47 -08005991
5992 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5993 try {
5994 response.onResult(result);
5995 } catch (RemoteException e) {
5996 // if the caller is dead then there is no one to care about remote
5997 // exceptions
5998 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5999 Log.v(TAG, "failure while notifying response", e);
6000 }
6001 }
6002 }
6003
6004 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6005 String errorMessage) {
6006 try {
6007 response.onError(errorCode, errorMessage);
6008 } catch (RemoteException e) {
6009 // if the caller is dead then there is no one to care about remote
6010 // exceptions
6011 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6012 Log.v(TAG, "failure while notifying response", e);
6013 }
6014 }
6015 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006016
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006017 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07006018 private final Object mLock = new Object();
6019
6020 @GuardedBy("mLock")
6021 private AccountManagerBackupHelper mBackupHelper;
6022
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006023 @Override
6024 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6025 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6026 if (account == null) {
6027 Slog.w(TAG, "account cannot be null");
6028 return;
6029 }
6030 if (packageName == null) {
6031 Slog.w(TAG, "packageName cannot be null");
6032 return;
6033 }
6034 if (userId < UserHandle.USER_SYSTEM) {
6035 Slog.w(TAG, "user id must be concrete");
6036 return;
6037 }
6038 if (callback == null) {
6039 Slog.w(TAG, "callback cannot be null");
6040 return;
6041 }
6042
Dmitry Dementyev7b3ea132017-05-10 12:45:02 -07006043 int visibility =
6044 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6045 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6046 Slog.w(TAG, "requestAccountAccess: account is hidden");
6047 return;
6048 }
6049
Svet Ganovf6d424f12016-09-20 20:18:53 -07006050 if (AccountManagerService.this.hasAccountAccess(account, packageName,
6051 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006052 Bundle result = new Bundle();
6053 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6054 callback.sendResult(result);
6055 return;
6056 }
6057
6058 final int uid;
6059 try {
6060 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6061 } catch (NameNotFoundException e) {
6062 Slog.e(TAG, "Unknown package " + packageName);
6063 return;
6064 }
6065
6066 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006067 final UserAccounts userAccounts;
6068 synchronized (mUsers) {
6069 userAccounts = mUsers.get(userId);
6070 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04006071 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006072 doNotification(userAccounts, account, null, intent, packageName, userId);
6073 }
6074
6075 @Override
6076 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6077 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6078 mAppPermissionChangeListeners.add(listener);
6079 }
6080
6081 @Override
6082 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6083 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006084 }
Svet Ganov5d09c992016-09-07 09:57:41 -07006085
6086 @Override
6087 public byte[] backupAccountAccessPermissions(int userId) {
6088 synchronized (mLock) {
6089 if (mBackupHelper == null) {
6090 mBackupHelper = new AccountManagerBackupHelper(
6091 AccountManagerService.this, this);
6092 }
6093 return mBackupHelper.backupAccountAccessPermissions(userId);
6094 }
6095 }
6096
6097 @Override
6098 public void restoreAccountAccessPermissions(byte[] data, int userId) {
6099 synchronized (mLock) {
6100 if (mBackupHelper == null) {
6101 mBackupHelper = new AccountManagerBackupHelper(
6102 AccountManagerService.this, this);
6103 }
6104 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6105 }
6106 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006107 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07006108
6109 @VisibleForTesting
6110 static class Injector {
6111 private final Context mContext;
6112
6113 public Injector(Context context) {
6114 mContext = context;
6115 }
6116
6117 Looper getMessageHandlerLooper() {
6118 ServiceThread serviceThread = new ServiceThread(TAG,
6119 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6120 serviceThread.start();
6121 return serviceThread.getLooper();
6122 }
6123
6124 Context getContext() {
6125 return mContext;
6126 }
6127
6128 void addLocalService(AccountManagerInternal service) {
6129 LocalServices.addService(AccountManagerInternal.class, service);
6130 }
6131
6132 String getDeDatabaseName(int userId) {
6133 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6134 AccountsDb.DE_DATABASE_NAME);
6135 return databaseFile.getPath();
6136 }
6137
6138 String getCeDatabaseName(int userId) {
6139 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6140 AccountsDb.CE_DATABASE_NAME);
6141 return databaseFile.getPath();
6142 }
6143
6144 String getPreNDatabaseName(int userId) {
6145 File systemDir = Environment.getDataSystemDirectory();
6146 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6147 PRE_N_DATABASE_NAME);
6148 if (userId == 0) {
6149 // Migrate old file, if it exists, to the new location.
6150 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006151 // accidentally created in the old location,
6152 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07006153 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6154 if (oldFile.exists() && !databaseFile.exists()) {
6155 // Check for use directory; create if it doesn't exist, else renameTo will fail
6156 File userDir = Environment.getUserSystemDirectory(userId);
6157 if (!userDir.exists()) {
6158 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006159 throw new IllegalStateException(
6160 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006161 }
6162 }
6163 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006164 throw new IllegalStateException(
6165 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006166 }
6167 }
6168 }
6169 return databaseFile.getPath();
6170 }
6171
6172 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6173 return new AccountAuthenticatorCache(mContext);
6174 }
6175
6176 INotificationManager getNotificationManager() {
6177 return NotificationManager.getService();
6178 }
6179 }
Chris Wren717a8812017-03-31 15:34:39 -04006180
6181 private class NotificationId {
6182 final String mTag;
6183 private final int mId;
6184
6185 NotificationId(String tag, int type) {
6186 mTag = tag;
6187 mId = type;
6188 }
6189 }
Fred Quintana60307342009-03-24 22:48:12 -07006190}