blob: 7fac66636be7a3f7a485d09ac49904438eee80f9 [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
sunjian066aa5e2017-06-05 12:16:59 -0700754 private boolean isVisible(int visibility) {
755 return visibility == AccountManager.VISIBILITY_VISIBLE ||
756 visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
757 }
758
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700759 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800760 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700761 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800762 * @param account Account to update visibility.
763 * @param packageName Package name for which visibility is updated.
764 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800765 * @param notify if the flag is set applications will get notification about visibility change
766 * @param accounts UserAccount that currently hosts the account and application
767 *
768 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700769 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800770 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800771 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700772 synchronized (accounts.dbLock) {
773 synchronized (accounts.cacheLock) {
774 Map<String, Integer> packagesToVisibility;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700775 List<String> accountRemovedReceivers;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700776 if (notify) {
777 if (isSpecialPackageKey(packageName)) {
778 packagesToVisibility =
779 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700780 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700781 } else {
782 if (!packageExistsForUser(packageName, accounts.userId)) {
783 return false; // package is not installed.
784 }
785 packagesToVisibility = new HashMap<>();
786 packagesToVisibility.put(packageName,
787 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700788 accountRemovedReceivers = new ArrayList<>();
789 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
790 accountRemovedReceivers.add(packageName);
791 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700792 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800793 } else {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700794 // Notifications will not be send - only used during add account.
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700795 if (!isSpecialPackageKey(packageName) &&
796 !packageExistsForUser(packageName, accounts.userId)) {
797 // package is not installed and not meta value.
798 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100799 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700800 packagesToVisibility = Collections.emptyMap();
801 accountRemovedReceivers = Collections.emptyList();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800802 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700803
804 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800805 return false;
806 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800807
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700808 if (notify) {
809 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
810 .entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -0700811 int oldVisibility = packageToVisibility.getValue();
812 int currentVisibility =
813 resolveAccountVisibility(account, packageName, accounts);
814 if (isVisible(oldVisibility) != isVisible(currentVisibility)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700815 notifyPackage(packageToVisibility.getKey(), accounts);
816 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700817 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700818 for (String packageNameToNotify : accountRemovedReceivers) {
819 sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
820 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700821 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700822 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700823 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800824 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700825 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700826 }
827
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700828 // Update account visibility in cache and database.
829 private boolean updateAccountVisibilityLocked(Account account, String packageName,
830 int newVisibility, UserAccounts accounts) {
831 final long accountId = accounts.accountsDb.findDeAccountId(account);
832 if (accountId < 0) {
833 return false;
834 }
835
836 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
837 try {
838 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
839 newVisibility)) {
840 return false;
841 }
842 } finally {
843 StrictMode.setThreadPolicy(oldPolicy);
844 }
845 Map<String, Integer> accountVisibility =
846 getPackagesAndVisibilityForAccountLocked(account, accounts);
847 accountVisibility.put(packageName, newVisibility);
848 return true;
849 }
850
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700851 @Override
852 public void registerAccountListener(String[] accountTypes, String opPackageName) {
853 int callingUid = Binder.getCallingUid();
854 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700855
856 int userId = UserHandle.getCallingUserId();
857 long identityToken = clearCallingIdentity();
858 try {
859 UserAccounts accounts = getUserAccounts(userId);
860 registerAccountListener(accountTypes, opPackageName, accounts);
861 } finally {
862 restoreCallingIdentity(identityToken);
863 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800864 }
865
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700866 private void registerAccountListener(String[] accountTypes, String opPackageName,
867 UserAccounts accounts) {
868 synchronized (accounts.mReceiversForType) {
869 if (accountTypes == null) {
870 // null for any type
871 accountTypes = new String[] {null};
872 }
873 for (String type : accountTypes) {
874 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
875 if (receivers == null) {
876 receivers = new HashMap<>();
877 accounts.mReceiversForType.put(type, receivers);
878 }
879 Integer cnt = receivers.get(opPackageName);
880 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800881 }
882 }
883 }
884
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700885 @Override
886 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
887 int callingUid = Binder.getCallingUid();
888 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700889 int userId = UserHandle.getCallingUserId();
890 long identityToken = clearCallingIdentity();
891 try {
892 UserAccounts accounts = getUserAccounts(userId);
893 unregisterAccountListener(accountTypes, opPackageName, accounts);
894 } finally {
895 restoreCallingIdentity(identityToken);
896 }
897 }
898
899 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
900 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700901 synchronized (accounts.mReceiversForType) {
902 if (accountTypes == null) {
903 // null for any type
904 accountTypes = new String[] {null};
905 }
906 for (String type : accountTypes) {
907 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
908 if (receivers == null || receivers.get(opPackageName) == null) {
909 throw new IllegalArgumentException("attempt to unregister wrong receiver");
910 }
911 Integer cnt = receivers.get(opPackageName);
912 if (cnt == 1) {
913 receivers.remove(opPackageName);
914 } else {
915 receivers.put(opPackageName, cnt - 1);
916 }
917 }
918 }
919 }
920
921 // Send notification to all packages which can potentially see the account
922 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
923 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700924
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700925 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700926 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
927 && (packageToVisibility.getValue()
928 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700929 notifyPackage(packageToVisibility.getKey(), accounts);
930 }
931 }
932 }
933
934 /**
935 * Sends a direct intent to a package, notifying it of account visibility change.
936 *
937 * @param packageName to send Account to
938 * @param accounts UserAccount that currently hosts the account
939 */
940 private void notifyPackage(String packageName, UserAccounts accounts) {
941 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
942 intent.setPackage(packageName);
943 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
944 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
945 }
946
947 // Returns a map from package name to visibility, for packages subscribed
948 // to notifications about any account type, or type of provided account
949 // account type or all types.
950 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
951 Set<String> packages = new HashSet<>();
952 synchronized (accounts.mReceiversForType) {
953 for (String type : new String[] {account.type, null}) {
954 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
955 if (receivers != null) {
956 packages.addAll(receivers.keySet());
957 }
958 }
959 }
960 Map<String, Integer> result = new HashMap<>();
961 for (String packageName : packages) {
962 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
963 }
964 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800965 }
966
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700967 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
968 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
969 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
970 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
971 List<ResolveInfo> receivers =
972 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
973 List<String> result = new ArrayList<>();
974 if (receivers == null) {
975 return result;
976 }
977 for (ResolveInfo resolveInfo: receivers) {
978 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
979 int visibility = resolveAccountVisibility(account, packageName, accounts);
980 if (visibility == AccountManager.VISIBILITY_VISIBLE
981 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
982 result.add(packageName);
983 }
984 }
985 return result;
986 }
987
988 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
989 private boolean shouldNotifyPackageOnAccountRemoval(Account account,
990 String packageName, UserAccounts accounts) {
991 int visibility = resolveAccountVisibility(account, packageName, accounts);
992 if (visibility != AccountManager.VISIBILITY_VISIBLE
993 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
994 return false;
995 }
996
997 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
998 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
999 intent.setPackage(packageName);
1000 List<ResolveInfo> receivers =
1001 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1002 return (receivers != null && receivers.size() > 0);
1003 }
1004
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001005 private boolean packageExistsForUser(String packageName, int userId) {
1006 try {
1007 long identityToken = clearCallingIdentity();
1008 try {
1009 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -07001010 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001011 } finally {
1012 restoreCallingIdentity(identityToken);
1013 }
1014 } catch (NameNotFoundException e) {
1015 return false;
1016 }
1017 }
1018
1019 /**
1020 * Returns true if packageName is one of special values.
1021 */
1022 private boolean isSpecialPackageKey(String packageName) {
1023 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1024 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1025 }
1026
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001027 private void sendAccountsChangedBroadcast(int userId) {
1028 Log.i(TAG, "the accounts changed, sending broadcast of "
1029 + ACCOUNTS_CHANGED_INTENT.getAction());
1030 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001031 }
1032
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001033 private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001034 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1035 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001036 intent.setPackage(packageName);
1037 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1038 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001039 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1040 }
1041
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001042 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -07001043 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1044 throws RemoteException {
1045 try {
1046 return super.onTransact(code, data, reply, flags);
1047 } catch (RuntimeException e) {
1048 // The account manager only throws security exceptions, so let's
1049 // log all others.
1050 if (!(e instanceof SecurityException)) {
1051 Slog.wtf(TAG, "Account Manager Crash", e);
1052 }
1053 throw e;
1054 }
1055 }
1056
Amith Yamasani258848d2012-08-10 17:06:33 -07001057 private UserManager getUserManager() {
1058 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -07001059 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -07001060 }
1061 return mUserManager;
1062 }
1063
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001064 /**
1065 * Validate internal set of accounts against installed authenticators for
1066 * given user. Clears cached authenticators before validating.
1067 */
1068 public void validateAccounts(int userId) {
1069 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001070 // Invalidate user-specific cache to make sure we catch any
1071 // removed authenticators.
1072 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1073 }
1074
1075 /**
1076 * Validate internal set of accounts against installed authenticators for
1077 * given user. Clear cached authenticators before validating when requested.
1078 */
1079 private void validateAccountsInternal(
1080 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001081 if (Log.isLoggable(TAG, Log.DEBUG)) {
1082 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001083 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001084 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001085 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001086
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001087 if (invalidateAuthenticatorCache) {
1088 mAuthenticatorCache.invalidateCache(accounts.userId);
1089 }
1090
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001091 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1092 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001093 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001094
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001095 synchronized (accounts.dbLock) {
1096 synchronized (accounts.cacheLock) {
1097 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001098
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001099 // Get a map of stored authenticator types to UID
1100 final AccountsDb accountsDb = accounts.accountsDb;
1101 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1102 // Create a list of authenticator type whose previous uid no longer exists
1103 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1104 SparseBooleanArray knownUids = null;
1105 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1106 String type = authToUidEntry.getKey();
1107 int uid = authToUidEntry.getValue();
1108 Integer knownUid = knownAuth.get(type);
1109 if (knownUid != null && uid == knownUid) {
1110 // Remove it from the knownAuth list if it's unchanged.
1111 knownAuth.remove(type);
1112 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001113 /*
1114 * The authenticator is presently not cached and should only be triggered
1115 * when we think an authenticator has been removed (or is being updated).
1116 * But we still want to check if any data with the associated uid is
1117 * around. This is an (imperfect) signal that the package may be updating.
1118 *
1119 * A side effect of this is that an authenticator sharing a uid with
1120 * multiple apps won't get its credentials wiped as long as some app with
1121 * that uid is still on the device. But I suspect that this is a rare case.
1122 * And it isn't clear to me how an attacker could really exploit that
1123 * feature.
1124 *
1125 * The upshot is that we don't have to worry about accounts getting
1126 * uninstalled while the authenticator's package is being updated.
1127 *
1128 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001129 if (knownUids == null) {
1130 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1131 }
1132 if (!knownUids.get(uid)) {
1133 // The authenticator is not presently available to the cache. And the
1134 // package no longer has a data directory (so we surmise it isn't
1135 // updating). So purge its data from the account databases.
1136 obsoleteAuthType.add(type);
1137 // And delete it from the TABLE_META
1138 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1139 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001140 }
1141 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001142
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001143 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1144 // been re-enabled (after being updated for example), then we just overwrite the old
1145 // values.
1146 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1147 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1148 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001149
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001150 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1151 try {
1152 accounts.accountCache.clear();
1153 final HashMap<String, ArrayList<String>> accountNamesByType
1154 = new LinkedHashMap<>();
1155 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1156 final long accountId = accountEntry.getKey();
1157 final Account account = accountEntry.getValue();
1158 if (obsoleteAuthType.contains(account.type)) {
1159 Slog.w(TAG, "deleting account " + account.name + " because type "
1160 + account.type
1161 + "'s registered authenticator no longer exist.");
1162 Map<String, Integer> packagesToVisibility =
1163 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001164 List<String> accountRemovedReceivers =
1165 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001166 accountsDb.beginTransaction();
1167 try {
1168 accountsDb.deleteDeAccount(accountId);
1169 // Also delete from CE table if user is unlocked; if user is
1170 // currently locked the account will be removed later by
1171 // syncDeCeAccountsLocked
1172 if (userUnlocked) {
1173 accountsDb.deleteCeAccount(accountId);
1174 }
1175 accountsDb.setTransactionSuccessful();
1176 } finally {
1177 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001178 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001179 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001180
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001181 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1182 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001183
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001184 accounts.userDataCache.remove(account);
1185 accounts.authTokenCache.remove(account);
1186 accounts.accountTokenCaches.remove(account);
1187 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001188
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001189 for (Entry<String, Integer> packageToVisibility :
1190 packagesToVisibility.entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -07001191 if (isVisible(packageToVisibility.getValue())) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001192 notifyPackage(packageToVisibility.getKey(), accounts);
1193 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001194 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001195 for (String packageName : accountRemovedReceivers) {
1196 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1197 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001198 } else {
1199 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1200 if (accountNames == null) {
1201 accountNames = new ArrayList<>();
1202 accountNamesByType.put(account.type, accountNames);
1203 }
1204 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001205 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001206 }
1207 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1208 final String accountType = cur.getKey();
1209 final ArrayList<String> accountNames = cur.getValue();
1210 final Account[] accountsForType = new Account[accountNames.size()];
1211 for (int i = 0; i < accountsForType.length; i++) {
1212 accountsForType[i] = new Account(accountNames.get(i), accountType,
1213 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001214 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001215 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001216 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001217 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1218 } finally {
1219 if (accountDeleted) {
1220 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001221 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001222 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001223 }
1224 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001225 }
1226
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001227 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1228 // Get the UIDs of all apps that might have data on the device. We want
1229 // to preserve user data if the app might otherwise be storing data.
1230 List<PackageInfo> pkgsWithData =
1231 mPackageManager.getInstalledPackagesAsUser(
1232 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1233 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1234 for (PackageInfo pkgInfo : pkgsWithData) {
1235 if (pkgInfo.applicationInfo != null
1236 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1237 knownUids.put(pkgInfo.applicationInfo.uid, true);
1238 }
1239 }
1240 return knownUids;
1241 }
1242
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001243 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001244 Context context,
1245 int userId) {
1246 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001247 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1248 }
1249
1250 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1251 IAccountAuthenticatorCache authCache,
1252 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001253 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001254 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1255 .getAllServices(userId)) {
1256 knownAuth.put(service.type.type, service.uid);
1257 }
1258 return knownAuth;
1259 }
1260
Amith Yamasani04e0d262012-02-14 11:50:53 -08001261 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001262 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001263 }
1264
1265 protected UserAccounts getUserAccounts(int userId) {
1266 synchronized (mUsers) {
1267 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001268 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001269 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001270 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1271 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001272 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001273 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001274 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001275 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001276 validateAccounts = true;
1277 }
1278 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001279 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001280 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001281 synchronized (accounts.dbLock) {
1282 synchronized (accounts.cacheLock) {
1283 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1284 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1285 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001286 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001287 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001288 }
1289 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001290 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001291 }
1292 return accounts;
1293 }
1294 }
1295
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001296 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1297 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001298 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001299 if (!accountsToRemove.isEmpty()) {
1300 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1301 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001302 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1303 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001304
1305 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001306 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001307 }
1308 }
1309 }
1310
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001311 private void purgeOldGrantsAll() {
1312 synchronized (mUsers) {
1313 for (int i = 0; i < mUsers.size(); i++) {
1314 purgeOldGrants(mUsers.valueAt(i));
1315 }
1316 }
1317 }
1318
1319 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001320 synchronized (accounts.dbLock) {
1321 synchronized (accounts.cacheLock) {
1322 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1323 for (int uid : uids) {
1324 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1325 if (packageExists) {
1326 continue;
1327 }
1328 Log.d(TAG, "deleting grants for UID " + uid
1329 + " because its package is no longer installed");
1330 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001331 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001332 }
1333 }
1334 }
1335
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001336 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001337 if (isSpecialPackageKey(packageName)) {
1338 return;
1339 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001340 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001341 int numberOfUsers = mUsers.size();
1342 for (int i = 0; i < numberOfUsers; i++) {
1343 UserAccounts accounts = mUsers.valueAt(i);
1344 try {
1345 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1346 } catch (NameNotFoundException e) {
1347 // package does not exist - remove visibility values
1348 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001349 synchronized (accounts.dbLock) {
1350 synchronized (accounts.cacheLock) {
1351 for (Account account : accounts.visibilityCache.keySet()) {
1352 Map<String, Integer> accountVisibility =
1353 getPackagesAndVisibilityForAccountLocked(account, accounts);
1354 accountVisibility.remove(packageName);
1355 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001356 }
1357 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001358 }
1359 }
1360 }
1361 }
1362
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001363
Fyodor Kupolovce25ed22017-05-04 11:44:31 -07001364 private void onStopUser(int userId) {
1365 Log.i(TAG, "onStopUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001366 UserAccounts accounts;
1367 synchronized (mUsers) {
1368 accounts = mUsers.get(userId);
1369 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001370 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001371 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001372 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001373 synchronized (accounts.dbLock) {
1374 synchronized (accounts.cacheLock) {
Fyodor Kupolov56e158f2017-05-23 16:41:51 -07001375 accounts.statementForLogging.close();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001376 accounts.accountsDb.close();
1377 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001378 }
Amith Yamasani13593602012-03-22 16:16:17 -07001379 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001380 }
1381
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001382 @VisibleForTesting
1383 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001384 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1385 }
1386
1387 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001388 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1389 Log.v(TAG, "onUserUnlocked " + userId);
1390 }
1391 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001392 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001393 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001394 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001395 syncSharedAccounts(userId);
1396 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001397
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001398 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001399 // Check if there's a shared account that needs to be created as an account
1400 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1401 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001402 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001403 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001404 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001405 : UserHandle.USER_SYSTEM;
1406 if (parentUserId < 0) {
1407 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1408 return;
1409 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001410 for (Account sa : sharedAccounts) {
1411 if (ArrayUtils.contains(accounts, sa)) continue;
1412 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001413 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001414 }
1415 }
1416
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001417 @Override
1418 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001419 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001420 }
1421
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001422 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001423 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001424 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001425 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1426 Log.v(TAG, "getPassword: " + account
1427 + ", caller's uid " + Binder.getCallingUid()
1428 + ", pid " + Binder.getCallingPid());
1429 }
Fred Quintana382601f2010-03-25 12:25:10 -07001430 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001431 int userId = UserHandle.getCallingUserId();
1432 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001433 String msg = String.format(
1434 "uid %s cannot get secrets for accounts of type: %s",
1435 callingUid,
1436 account.type);
1437 throw new SecurityException(msg);
1438 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001439 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001440 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001441 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001442 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001443 } finally {
1444 restoreCallingIdentity(identityToken);
1445 }
1446 }
1447
Amith Yamasani04e0d262012-02-14 11:50:53 -08001448 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001449 if (account == null) {
1450 return null;
1451 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001452 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001453 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1454 return null;
1455 }
Fred Quintana31957f12009-10-21 13:43:10 -07001456
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001457 synchronized (accounts.dbLock) {
1458 synchronized (accounts.cacheLock) {
1459 return accounts.accountsDb
1460 .findAccountPasswordByNameAndType(account.name, account.type);
1461 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001462 }
1463 }
1464
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001465 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001466 public String getPreviousName(Account account) {
1467 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1468 Log.v(TAG, "getPreviousName: " + account
1469 + ", caller's uid " + Binder.getCallingUid()
1470 + ", pid " + Binder.getCallingPid());
1471 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001472 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001473 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001474 long identityToken = clearCallingIdentity();
1475 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001476 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001477 return readPreviousNameInternal(accounts, account);
1478 } finally {
1479 restoreCallingIdentity(identityToken);
1480 }
1481 }
1482
1483 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1484 if (account == null) {
1485 return null;
1486 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001487 synchronized (accounts.dbLock) {
1488 synchronized (accounts.cacheLock) {
1489 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1490 if (previousNameRef == null) {
1491 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1492 previousNameRef = new AtomicReference<>(previousName);
1493 accounts.previousNameCache.put(account, previousNameRef);
1494 return previousName;
1495 } else {
1496 return previousNameRef.get();
1497 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001498 }
1499 }
1500 }
1501
1502 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001503 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001504 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001505 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001506 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1507 account, key, callingUid, Binder.getCallingPid());
1508 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001509 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001510 Preconditions.checkNotNull(account, "account cannot be null");
1511 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001512 int userId = UserHandle.getCallingUserId();
1513 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001514 String msg = String.format(
1515 "uid %s cannot get user data for accounts of type: %s",
1516 callingUid,
1517 account.type);
1518 throw new SecurityException(msg);
1519 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001520 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001521 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1522 return null;
1523 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001524 long identityToken = clearCallingIdentity();
1525 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001526 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001527 if (!accountExistsCache(accounts, account)) {
1528 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001529 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001530 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001531 } finally {
1532 restoreCallingIdentity(identityToken);
1533 }
1534 }
1535
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001536 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001537 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001538 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001539 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1540 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001541 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001542 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001543 + ", pid " + Binder.getCallingPid());
1544 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001545 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001546 if (isCrossUser(callingUid, userId)) {
1547 throw new SecurityException(
1548 String.format(
1549 "User %s tying to get authenticator types for %s" ,
1550 UserHandle.getCallingUserId(),
1551 userId));
1552 }
1553
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001554 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001555 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001556 return getAuthenticatorTypesInternal(userId);
1557
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001558 } finally {
1559 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001560 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001561 }
1562
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001563 /**
1564 * Should only be called inside of a clearCallingIdentity block.
1565 */
1566 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001567 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001568 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1569 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1570 AuthenticatorDescription[] types =
1571 new AuthenticatorDescription[authenticatorCollection.size()];
1572 int i = 0;
1573 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1574 : authenticatorCollection) {
1575 types[i] = authenticator.type;
1576 i++;
1577 }
1578 return types;
1579 }
1580
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001581 private boolean isCrossUser(int callingUid, int userId) {
1582 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001583 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001584 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001585 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1586 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001587 }
1588
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001589 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001590 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001591 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001592 }
1593
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001594 @Override
1595 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001596 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001597 int callingUid = Binder.getCallingUid();
1598 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1599 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001600 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001601 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001602 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1603 final UserAccounts toAccounts = getUserAccounts(userTo);
1604 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001605 if (response != null) {
1606 Bundle result = new Bundle();
1607 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1608 try {
1609 response.onResult(result);
1610 } catch (RemoteException e) {
1611 Slog.w(TAG, "Failed to report error back to the client." + e);
1612 }
1613 }
1614 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001615 }
1616
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001617 Slog.d(TAG, "Copying account " + account.name
1618 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001619 long identityToken = clearCallingIdentity();
1620 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001621 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001622 false /* stripAuthTokenFromResult */, account.name,
1623 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001624 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001625 protected String toDebugString(long now) {
1626 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1627 + ", " + account.type;
1628 }
1629
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001630 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001631 public void run() throws RemoteException {
1632 mAuthenticator.getAccountCredentialsForCloning(this, account);
1633 }
1634
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001635 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001636 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001637 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001638 if (result != null
1639 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1640 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001641 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001642 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001643 super.onResult(result);
1644 }
1645 }
1646 }.bind();
1647 } finally {
1648 restoreCallingIdentity(identityToken);
1649 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001650 }
1651
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001652 @Override
1653 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001654 final int callingUid = Binder.getCallingUid();
1655 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1656 String msg = String.format(
1657 "accountAuthenticated( account: %s, callerUid: %s)",
1658 account,
1659 callingUid);
1660 Log.v(TAG, msg);
1661 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001662 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001663 int userId = UserHandle.getCallingUserId();
1664 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001665 String msg = String.format(
1666 "uid %s cannot notify authentication for accounts of type: %s",
1667 callingUid,
1668 account.type);
1669 throw new SecurityException(msg);
1670 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001671
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001672 if (!canUserModifyAccounts(userId, callingUid) ||
1673 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001674 return false;
1675 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001676
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001677 long identityToken = clearCallingIdentity();
1678 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001679 UserAccounts accounts = getUserAccounts(userId);
1680 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001681 } finally {
1682 restoreCallingIdentity(identityToken);
1683 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001684 }
1685
1686 private boolean updateLastAuthenticatedTime(Account account) {
1687 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001688 synchronized (accounts.dbLock) {
1689 synchronized (accounts.cacheLock) {
1690 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1691 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001692 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001693 }
1694
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001695 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001696 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1697 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001698 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001699 long id = clearCallingIdentity();
1700 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001701 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001702 false /* stripAuthTokenFromResult */, account.name,
1703 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001704 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001705 protected String toDebugString(long now) {
1706 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1707 + ", " + account.type;
1708 }
1709
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001710 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001711 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001712 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001713 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1714 if (acc.equals(account)) {
1715 mAuthenticator.addAccountFromCredentials(
1716 this, account, accountCredentials);
1717 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001718 }
1719 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001720 }
1721
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001722 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001723 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001724 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001725 // TODO: Anything to do if if succedded?
1726 // TODO: If it failed: Show error notification? Should we remove the shadow
1727 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001728 // TODO: what we do with the visibility?
1729
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001730 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001731 }
1732
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001733 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001734 public void onError(int errorCode, String errorMessage) {
1735 super.onError(errorCode, errorMessage);
1736 // TODO: Show error notification to user
1737 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1738 }
1739
1740 }.bind();
1741 } finally {
1742 restoreCallingIdentity(id);
1743 }
1744 }
1745
Amith Yamasani04e0d262012-02-14 11:50:53 -08001746 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001747 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001748 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001749 if (account == null) {
1750 return false;
1751 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001752 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001753 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1754 + " is locked. callingUid=" + callingUid);
1755 return false;
1756 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001757 synchronized (accounts.dbLock) {
1758 synchronized (accounts.cacheLock) {
1759 accounts.accountsDb.beginTransaction();
1760 try {
1761 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1762 Log.w(TAG, "insertAccountIntoDatabase: " + account
1763 + ", skipping since the account already exists");
1764 return false;
1765 }
1766 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1767 if (accountId < 0) {
1768 Log.w(TAG, "insertAccountIntoDatabase: " + account
1769 + ", skipping the DB insert failed");
1770 return false;
1771 }
1772 // Insert into DE table
1773 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1774 Log.w(TAG, "insertAccountIntoDatabase: " + account
1775 + ", skipping the DB insert failed");
1776 return false;
1777 }
1778 if (extras != null) {
1779 for (String key : extras.keySet()) {
1780 final String value = extras.getString(key);
1781 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1782 Log.w(TAG, "insertAccountIntoDatabase: " + account
1783 + ", skipping since insertExtra failed for key " + key);
1784 return false;
1785 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001786 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001787 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001788
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001789 if (packageToVisibility != null) {
1790 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1791 setAccountVisibility(account, entry.getKey() /* package */,
1792 entry.getValue() /* visibility */, false /* notify */,
1793 accounts);
1794 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001795 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001796 accounts.accountsDb.setTransactionSuccessful();
1797
1798 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1799 accountId,
1800 accounts, callingUid);
1801
1802 insertAccountIntoCacheLocked(accounts, account);
1803 } finally {
1804 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001805 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001806 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001807 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001808 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1809 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001810 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001811
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001812 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001813 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1814 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001815
Amith Yamasani5be347b2013-03-31 17:44:31 -07001816 return true;
1817 }
1818
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001819 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001820 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001821 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001822 }
1823 }
1824
Amith Yamasani5be347b2013-03-31 17:44:31 -07001825 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001826 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001827 * running, then clone the account too.
1828 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001829 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001830 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001831 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001832 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001833 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001834 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001835 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001836 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001837 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001838 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001839 }
1840 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001841 }
1842 }
1843
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001844 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001845 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001846 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001847 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001848 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001849 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1850 Log.v(TAG, "hasFeatures: " + account
1851 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001852 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001853 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001854 + ", pid " + Binder.getCallingPid());
1855 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001856 Preconditions.checkArgument(account != null, "account cannot be null");
1857 Preconditions.checkArgument(response != null, "response cannot be null");
1858 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001859 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001860 checkReadAccountsPermitted(callingUid, account.type, userId,
1861 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001862
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001863 long identityToken = clearCallingIdentity();
1864 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001865 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001866 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001867 } finally {
1868 restoreCallingIdentity(identityToken);
1869 }
1870 }
1871
1872 private class TestFeaturesSession extends Session {
1873 private final String[] mFeatures;
1874 private final Account mAccount;
1875
Amith Yamasani04e0d262012-02-14 11:50:53 -08001876 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001877 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001878 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001879 true /* stripAuthTokenFromResult */, account.name,
1880 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001881 mFeatures = features;
1882 mAccount = account;
1883 }
1884
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001885 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001886 public void run() throws RemoteException {
1887 try {
1888 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1889 } catch (RemoteException e) {
1890 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1891 }
1892 }
1893
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001894 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001895 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001896 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001897 IAccountManagerResponse response = getResponseAndClose();
1898 if (response != null) {
1899 try {
1900 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001901 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001902 return;
1903 }
Fred Quintana56285a62010-12-02 14:20:51 -08001904 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1905 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1906 + response);
1907 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001908 final Bundle newResult = new Bundle();
1909 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1910 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1911 response.onResult(newResult);
1912 } catch (RemoteException e) {
1913 // if the caller is dead then there is no one to care about remote exceptions
1914 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1915 Log.v(TAG, "failure while notifying response", e);
1916 }
1917 }
1918 }
1919 }
1920
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001921 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001922 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001923 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001924 + ", " + mAccount
1925 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1926 }
1927 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001928
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001929 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001930 public void renameAccount(
1931 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001932 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001933 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1934 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001935 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001936 + ", pid " + Binder.getCallingPid());
1937 }
1938 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001939 int userId = UserHandle.getCallingUserId();
1940 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001941 String msg = String.format(
1942 "uid %s cannot rename accounts of type: %s",
1943 callingUid,
1944 accountToRename.type);
1945 throw new SecurityException(msg);
1946 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001947 long identityToken = clearCallingIdentity();
1948 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001949 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001950 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001951 Bundle result = new Bundle();
1952 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1953 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001954 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1955 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001956 try {
1957 response.onResult(result);
1958 } catch (RemoteException e) {
1959 Log.w(TAG, e.getMessage());
1960 }
1961 } finally {
1962 restoreCallingIdentity(identityToken);
1963 }
1964 }
1965
1966 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001967 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001968 Account resultAccount = null;
1969 /*
1970 * Cancel existing notifications. Let authenticators
1971 * re-post notifications as required. But we don't know if
1972 * the authenticators have bound their notifications to
1973 * now stale account name data.
1974 *
1975 * With a rename api, we might not need to do this anymore but it
1976 * shouldn't hurt.
1977 */
1978 cancelNotification(
1979 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04001980 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001981 synchronized(accounts.credentialsPermissionNotificationIds) {
1982 for (Pair<Pair<Account, String>, Integer> pair:
1983 accounts.credentialsPermissionNotificationIds.keySet()) {
1984 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04001985 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001986 cancelNotification(id, new UserHandle(accounts.userId));
1987 }
1988 }
1989 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001990 synchronized (accounts.dbLock) {
1991 synchronized (accounts.cacheLock) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001992 List<String> accountRemovedReceivers =
1993 getAccountRemovedReceivers(accountToRename, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001994 accounts.accountsDb.beginTransaction();
1995 Account renamedAccount = new Account(newName, accountToRename.type);
1996 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1997 Log.e(TAG, "renameAccount failed - account with new name already exists");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001998 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001999 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002000 try {
2001 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2002 if (accountId >= 0) {
2003 accounts.accountsDb.renameCeAccount(accountId, newName);
2004 if (accounts.accountsDb.renameDeAccount(
2005 accountId, newName, accountToRename.name)) {
2006 accounts.accountsDb.setTransactionSuccessful();
2007 } else {
2008 Log.e(TAG, "renameAccount failed");
2009 return null;
2010 }
2011 } else {
2012 Log.e(TAG, "renameAccount failed - old account does not exist");
2013 return null;
2014 }
2015 } finally {
2016 accounts.accountsDb.endTransaction();
2017 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002018 /*
2019 * Database transaction was successful. Clean up cached
2020 * data associated with the account in the user profile.
2021 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002022 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002023 /*
2024 * Extract the data and token caches before removing the
2025 * old account to preserve the user data associated with
2026 * the account.
2027 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002028 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2029 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2030 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2031 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002032 /*
2033 * Update the cached data associated with the renamed
2034 * account.
2035 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002036 accounts.userDataCache.put(renamedAccount, tmpData);
2037 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2038 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2039 accounts.previousNameCache.put(
2040 renamedAccount,
2041 new AtomicReference<>(accountToRename.name));
2042 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002043
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002044 int parentUserId = accounts.userId;
2045 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002046 /*
2047 * Owner or system user account was renamed, rename the account for
2048 * those users with which the account was shared.
2049 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002050 List<UserInfo> users = getUserManager().getUsers(true);
2051 for (UserInfo user : users) {
2052 if (user.isRestricted()
2053 && (user.restrictedProfileParentId == parentUserId)) {
2054 renameSharedAccountAsUser(accountToRename, newName, user.id);
2055 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002056 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002057 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002058
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002059 sendNotificationAccountUpdated(resultAccount, accounts);
2060 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002061 for (String packageName : accountRemovedReceivers) {
2062 sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2063 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002064 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002065 }
2066 return resultAccount;
2067 }
2068
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002069 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002070 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002071 return userInfo != null && userInfo.canHaveProfile();
2072 }
2073
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002074 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002075 public void removeAccount(IAccountManagerResponse response, Account account,
2076 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002077 removeAccountAsUser(
2078 response,
2079 account,
2080 expectActivityLaunch,
2081 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002082 }
2083
2084 @Override
2085 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002086 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002087 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002088 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2089 Log.v(TAG, "removeAccount: " + account
2090 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002091 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002092 + ", pid " + Binder.getCallingPid()
2093 + ", for user id " + userId);
2094 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002095 Preconditions.checkArgument(account != null, "account cannot be null");
2096 Preconditions.checkArgument(response != null, "response cannot be null");
2097
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002098 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002099 if (isCrossUser(callingUid, userId)) {
2100 throw new SecurityException(
2101 String.format(
2102 "User %s tying remove account for %s" ,
2103 UserHandle.getCallingUserId(),
2104 userId));
2105 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002106 /*
2107 * Only the system or authenticator should be allowed to remove accounts for that
2108 * authenticator. This will let users remove accounts (via Settings in the system) but not
2109 * arbitrary applications (like competing authenticators).
2110 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002111 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002112 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
2113 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002114 String msg = String.format(
2115 "uid %s cannot remove accounts of type: %s",
2116 callingUid,
2117 account.type);
2118 throw new SecurityException(msg);
2119 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002120 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002121 try {
2122 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2123 "User cannot modify accounts");
2124 } catch (RemoteException re) {
2125 }
2126 return;
2127 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002128 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002129 try {
2130 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2131 "User cannot modify accounts of this type (policy).");
2132 } catch (RemoteException re) {
2133 }
2134 return;
2135 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002136 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002137 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002138 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002139 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002140 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002141 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002142 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002143 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002144 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002145 }
2146 }
2147 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002148 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002149 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002150 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2151 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002152 accountId,
2153 accounts,
2154 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002155 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002156 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2157 } finally {
2158 restoreCallingIdentity(identityToken);
2159 }
2160 }
2161
2162 @Override
2163 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002164 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002165 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2166 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002167 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002168 + ", pid " + Binder.getCallingPid());
2169 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002170 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002171 if (account == null) {
2172 /*
2173 * Null accounts should result in returning false, as per
2174 * AccountManage.addAccountExplicitly(...) java doc.
2175 */
2176 Log.e(TAG, "account is null");
2177 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002178 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002179 String msg = String.format(
2180 "uid %s cannot explicitly add accounts of type: %s",
2181 callingUid,
2182 account.type);
2183 throw new SecurityException(msg);
2184 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002185 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002186 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002187 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002188 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2189 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002190 accountId,
2191 accounts,
2192 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002193 long identityToken = clearCallingIdentity();
2194 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002195 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002196 } finally {
2197 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002198 }
Fred Quintana60307342009-03-24 22:48:12 -07002199 }
2200
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002201 private class RemoveAccountSession extends Session {
2202 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002203 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002204 Account account, boolean expectActivityLaunch) {
2205 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002206 true /* stripAuthTokenFromResult */, account.name,
2207 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002208 mAccount = account;
2209 }
2210
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002211 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002212 protected String toDebugString(long now) {
2213 return super.toDebugString(now) + ", removeAccount"
2214 + ", account " + mAccount;
2215 }
2216
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002217 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002218 public void run() throws RemoteException {
2219 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2220 }
2221
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002222 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002223 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002224 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002225 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2226 && !result.containsKey(AccountManager.KEY_INTENT)) {
2227 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002228 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002229 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002230 }
2231 IAccountManagerResponse response = getResponseAndClose();
2232 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002233 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2234 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2235 + response);
2236 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002237 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002238 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002239 try {
2240 response.onResult(result2);
2241 } catch (RemoteException e) {
2242 // ignore
2243 }
2244 }
2245 }
2246 super.onResult(result);
2247 }
2248 }
2249
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002250 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002251 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002252 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002253 }
2254
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002255 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002256 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002257 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002258 if (!userUnlocked) {
2259 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2260 + " is still locked. CE data will be removed later");
2261 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002262 synchronized (accounts.dbLock) {
2263 synchronized (accounts.cacheLock) {
2264 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2265 accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002266 List<String> accountRemovedReceivers =
2267 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002268 accounts.accountsDb.beginTransaction();
2269 // Set to a dummy value, this will only be used if the database
2270 // transaction succeeds.
2271 long accountId = -1;
2272 try {
2273 accountId = accounts.accountsDb.findDeAccountId(account);
2274 if (accountId >= 0) {
2275 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002276 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002277 // always delete from CE table if CE storage is available
2278 // DE account could be removed while CE was locked
2279 if (userUnlocked) {
2280 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2281 if (ceAccountId >= 0) {
2282 accounts.accountsDb.deleteCeAccount(ceAccountId);
2283 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002284 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002285 accounts.accountsDb.setTransactionSuccessful();
2286 } finally {
2287 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002288 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002289 if (isChanged) {
2290 removeAccountFromCacheLocked(accounts, account);
2291 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2292 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002293 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2294 || (packageToVisibility.getValue()
2295 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002296 notifyPackage(packageToVisibility.getKey(), accounts);
2297 }
2298 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002299
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002300 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2301 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002302 for (String packageName : accountRemovedReceivers) {
2303 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2304 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002305 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2306 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2307 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2308 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002309 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002310 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002311 long id = Binder.clearCallingIdentity();
2312 try {
2313 int parentUserId = accounts.userId;
2314 if (canHaveProfile(parentUserId)) {
2315 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002316 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002317 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002318 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002319 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002320 }
2321 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002322 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002323 } finally {
2324 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002325 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002326
2327 if (isChanged) {
2328 synchronized (accounts.credentialsPermissionNotificationIds) {
2329 for (Pair<Pair<Account, String>, Integer> key
2330 : accounts.credentialsPermissionNotificationIds.keySet()) {
2331 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002332 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002333 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002334 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002335 account, uid, false));
2336 }
2337 }
2338 }
2339 }
2340
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002341 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002342 }
2343
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002344 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002345 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002346 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002347 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2348 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002349 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2350 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002351 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002352 + ", pid " + Binder.getCallingPid());
2353 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002354 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002355 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002356 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002357 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002358 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002359 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002360 accounts.accountsDb.beginTransaction();
2361 try {
2362 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2363 accounts.accountsDb.setTransactionSuccessful();
2364 } finally {
2365 accounts.accountsDb.endTransaction();
2366 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002367 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002368 for (Pair<Account, String> tokenInfo : deletedTokens) {
2369 Account act = tokenInfo.first;
2370 String tokenType = tokenInfo.second;
2371 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002372 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002373 // wipe out cached token in memory.
2374 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002375 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002376 }
Fred Quintana60307342009-03-24 22:48:12 -07002377 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002378 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002379 }
2380 }
2381
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002382 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002383 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002384 // TODO Move to AccountsDB
2385 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002386 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002387
Fred Quintana33269202009-04-20 16:05:10 -07002388 try {
2389 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002390 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002391 String accountName = cursor.getString(1);
2392 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002393 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002394 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002395 }
Fred Quintana33269202009-04-20 16:05:10 -07002396 } finally {
2397 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002398 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002399 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002400 }
2401
Carlos Valdivia91979be2015-05-22 14:11:35 -07002402 private void saveCachedToken(
2403 UserAccounts accounts,
2404 Account account,
2405 String callerPkg,
2406 byte[] callerSigDigest,
2407 String tokenType,
2408 String token,
2409 long expiryMillis) {
2410
2411 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2412 return;
2413 }
2414 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002415 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002416 synchronized (accounts.cacheLock) {
2417 accounts.accountTokenCaches.put(
2418 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002419 }
2420 }
2421
Amith Yamasani04e0d262012-02-14 11:50:53 -08002422 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2423 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002424 if (account == null || type == null) {
2425 return false;
2426 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002427 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002428 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002429 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002430 accounts.accountsDb.beginTransaction();
2431 boolean updateCache = false;
2432 try {
2433 long accountId = accounts.accountsDb.findDeAccountId(account);
2434 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002435 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002436 }
2437 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2438 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2439 accounts.accountsDb.setTransactionSuccessful();
2440 updateCache = true;
2441 return true;
2442 }
2443 return false;
2444 } finally {
2445 accounts.accountsDb.endTransaction();
2446 if (updateCache) {
2447 synchronized (accounts.cacheLock) {
2448 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2449 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002450 }
Fred Quintana33269202009-04-20 16:05:10 -07002451 }
Fred Quintana60307342009-03-24 22:48:12 -07002452 }
2453 }
2454
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002455 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002456 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002457 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002458 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2459 Log.v(TAG, "peekAuthToken: " + account
2460 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002461 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002462 + ", pid " + Binder.getCallingPid());
2463 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002464 Preconditions.checkNotNull(account, "account cannot be null");
2465 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002466 int userId = UserHandle.getCallingUserId();
2467 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002468 String msg = String.format(
2469 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2470 callingUid,
2471 account.type);
2472 throw new SecurityException(msg);
2473 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002474 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002475 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2476 + callingUid);
2477 return null;
2478 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002479 long identityToken = clearCallingIdentity();
2480 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002481 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002482 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002483 } finally {
2484 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002485 }
Fred Quintana60307342009-03-24 22:48:12 -07002486 }
2487
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002488 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002489 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002490 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002491 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2492 Log.v(TAG, "setAuthToken: " + account
2493 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002494 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002495 + ", pid " + Binder.getCallingPid());
2496 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002497 Preconditions.checkNotNull(account, "account cannot be null");
2498 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002499 int userId = UserHandle.getCallingUserId();
2500 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002501 String msg = String.format(
2502 "uid %s cannot set auth tokens associated with accounts of type: %s",
2503 callingUid,
2504 account.type);
2505 throw new SecurityException(msg);
2506 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002507 long identityToken = clearCallingIdentity();
2508 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002509 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002510 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002511 } finally {
2512 restoreCallingIdentity(identityToken);
2513 }
Fred Quintana60307342009-03-24 22:48:12 -07002514 }
2515
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002516 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002517 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002518 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002519 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2520 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002521 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002522 + ", pid " + Binder.getCallingPid());
2523 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002524 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002525 int userId = UserHandle.getCallingUserId();
2526 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002527 String msg = String.format(
2528 "uid %s cannot set secrets for accounts of type: %s",
2529 callingUid,
2530 account.type);
2531 throw new SecurityException(msg);
2532 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002533 long identityToken = clearCallingIdentity();
2534 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002535 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002536 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002537 } finally {
2538 restoreCallingIdentity(identityToken);
2539 }
Fred Quintana60307342009-03-24 22:48:12 -07002540 }
2541
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002542 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2543 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002544 if (account == null) {
2545 return;
2546 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002547 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002548 synchronized (accounts.dbLock) {
2549 synchronized (accounts.cacheLock) {
2550 accounts.accountsDb.beginTransaction();
2551 try {
2552 final long accountId = accounts.accountsDb.findDeAccountId(account);
2553 if (accountId >= 0) {
2554 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2555 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2556 accounts.authTokenCache.remove(account);
2557 accounts.accountTokenCaches.remove(account);
2558 accounts.accountsDb.setTransactionSuccessful();
2559 // If there is an account whose password will be updated and the database
2560 // transactions succeed, then we say that a change has occured. Even if the
2561 // new password is the same as the old and there were no authtokens to
2562 // delete.
2563 isChanged = true;
2564 String action = (password == null || password.length() == 0) ?
2565 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2566 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2567 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2568 callingUid);
2569 }
2570 } finally {
2571 accounts.accountsDb.endTransaction();
2572 if (isChanged) {
2573 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2574 sendNotificationAccountUpdated(account, accounts);
2575 sendAccountsChangedBroadcast(accounts.userId);
2576 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002577 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002578 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002579 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002580 }
2581
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002582 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002583 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002584 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002585 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2586 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002587 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002588 + ", pid " + Binder.getCallingPid());
2589 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002590 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002591 int userId = UserHandle.getCallingUserId();
2592 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002593 String msg = String.format(
2594 "uid %s cannot clear passwords for accounts of type: %s",
2595 callingUid,
2596 account.type);
2597 throw new SecurityException(msg);
2598 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002599 long identityToken = clearCallingIdentity();
2600 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002601 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002602 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002603 } finally {
2604 restoreCallingIdentity(identityToken);
2605 }
Fred Quintana60307342009-03-24 22:48:12 -07002606 }
2607
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002608 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002609 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002610 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002611 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2612 Log.v(TAG, "setUserData: " + account
2613 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002614 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002615 + ", pid " + Binder.getCallingPid());
2616 }
Fred Quintana382601f2010-03-25 12:25:10 -07002617 if (key == null) throw new IllegalArgumentException("key is null");
2618 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002619 int userId = UserHandle.getCallingUserId();
2620 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002621 String msg = String.format(
2622 "uid %s cannot set user data for accounts of type: %s",
2623 callingUid,
2624 account.type);
2625 throw new SecurityException(msg);
2626 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002627 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002628 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002629 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002630 if (!accountExistsCache(accounts, account)) {
2631 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002632 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002633 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002634 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002635 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002636 }
2637 }
2638
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002639 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2640 synchronized (accounts.cacheLock) {
2641 if (accounts.accountCache.containsKey(account.type)) {
2642 for (Account acc : accounts.accountCache.get(account.type)) {
2643 if (acc.name.equals(account.name)) {
2644 return true;
2645 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002646 }
2647 }
2648 }
2649 return false;
2650 }
2651
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002652 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002653 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002654 synchronized (accounts.dbLock) {
2655 accounts.accountsDb.beginTransaction();
2656 try {
2657 long accountId = accounts.accountsDb.findDeAccountId(account);
2658 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002659 return;
2660 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002661 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2662 if (extrasId < 0) {
2663 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2664 if (extrasId < 0) {
2665 return;
2666 }
2667 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2668 return;
2669 }
2670 accounts.accountsDb.setTransactionSuccessful();
2671 } finally {
2672 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002673 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002674 synchronized (accounts.cacheLock) {
2675 writeUserDataIntoCacheLocked(accounts, account, key, value);
2676 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002677 }
2678 }
2679
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002680 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002681 if (result == null) {
2682 Log.e(TAG, "the result is unexpectedly null", new Exception());
2683 }
2684 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2685 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2686 + response);
2687 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002688 try {
2689 response.onResult(result);
2690 } catch (RemoteException e) {
2691 // if the caller is dead then there is no one to care about remote
2692 // exceptions
2693 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2694 Log.v(TAG, "failure while notifying response", e);
2695 }
2696 }
2697 }
2698
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002699 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002700 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2701 final String authTokenType)
2702 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002703 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2704 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002705
Fred Quintanad9640ec2012-05-23 12:37:00 -07002706 final int callingUid = getCallingUid();
2707 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002708 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002709 throw new SecurityException("can only call from system");
2710 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002711 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002712 long identityToken = clearCallingIdentity();
2713 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002714 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002715 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2716 false /* stripAuthTokenFromResult */, null /* accountName */,
2717 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002718 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002719 protected String toDebugString(long now) {
2720 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002721 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002722 + ", authTokenType " + authTokenType;
2723 }
2724
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002725 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002726 public void run() throws RemoteException {
2727 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2728 }
2729
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002730 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002731 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002732 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002733 if (result != null) {
2734 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2735 Bundle bundle = new Bundle();
2736 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2737 super.onResult(bundle);
2738 return;
2739 } else {
2740 super.onResult(result);
2741 }
2742 }
2743 }.bind();
2744 } finally {
2745 restoreCallingIdentity(identityToken);
2746 }
2747 }
2748
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002749 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002750 public void getAuthToken(
2751 IAccountManagerResponse response,
2752 final Account account,
2753 final String authTokenType,
2754 final boolean notifyOnAuthFailure,
2755 final boolean expectActivityLaunch,
2756 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002757 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002758 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2759 Log.v(TAG, "getAuthToken: " + account
2760 + ", response " + response
2761 + ", authTokenType " + authTokenType
2762 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2763 + ", expectActivityLaunch " + expectActivityLaunch
2764 + ", caller's uid " + Binder.getCallingUid()
2765 + ", pid " + Binder.getCallingPid());
2766 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002767 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002768 try {
2769 if (account == null) {
2770 Slog.w(TAG, "getAuthToken called with null account");
2771 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2772 return;
2773 }
2774 if (authTokenType == null) {
2775 Slog.w(TAG, "getAuthToken called with null authTokenType");
2776 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2777 return;
2778 }
2779 } catch (RemoteException e) {
2780 Slog.w(TAG, "Failed to report error back to the client." + e);
2781 return;
2782 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002783 int userId = UserHandle.getCallingUserId();
2784 long ident = Binder.clearCallingIdentity();
2785 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002786 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002787 try {
2788 accounts = getUserAccounts(userId);
2789 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2790 AuthenticatorDescription.newKey(account.type), accounts.userId);
2791 } finally {
2792 Binder.restoreCallingIdentity(ident);
2793 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002794
Costin Manolachea40c6302010-12-13 14:50:45 -08002795 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002796 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002797
2798 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002799 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002800 final boolean permissionGranted =
2801 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002802
Carlos Valdivia91979be2015-05-22 14:11:35 -07002803 // Get the calling package. We will use it for the purpose of caching.
2804 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002805 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002806 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002807 try {
2808 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2809 } finally {
2810 Binder.restoreCallingIdentity(ident);
2811 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002812 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2813 String msg = String.format(
2814 "Uid %s is attempting to illegally masquerade as package %s!",
2815 callerUid,
2816 callerPkg);
2817 throw new SecurityException(msg);
2818 }
2819
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002820 // let authenticator know the identity of the caller
2821 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2822 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002823
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002824 if (notifyOnAuthFailure) {
2825 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002826 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002827
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002828 long identityToken = clearCallingIdentity();
2829 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002830 // Distill the caller's package signatures into a single digest.
2831 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2832
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002833 // if the caller has permission, do the peek. otherwise go the more expensive
2834 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002835 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002836 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002837 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002838 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002839 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2840 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2841 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002842 onResult(response, result);
2843 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002844 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002845 }
2846
Carlos Valdivia91979be2015-05-22 14:11:35 -07002847 if (customTokens) {
2848 /*
2849 * Look up tokens in the new cache only if the loginOptions don't have parameters
2850 * outside of those expected to be injected by the AccountManager, e.g.
2851 * ANDORID_PACKAGE_NAME.
2852 */
2853 String token = readCachedTokenInternal(
2854 accounts,
2855 account,
2856 authTokenType,
2857 callerPkg,
2858 callerPkgSigDigest);
2859 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002860 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2861 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2862 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002863 Bundle result = new Bundle();
2864 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2865 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2866 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2867 onResult(response, result);
2868 return;
2869 }
2870 }
2871
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002872 new Session(
2873 accounts,
2874 response,
2875 account.type,
2876 expectActivityLaunch,
2877 false /* stripAuthTokenFromResult */,
2878 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002879 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002880 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002881 protected String toDebugString(long now) {
2882 if (loginOptions != null) loginOptions.keySet();
2883 return super.toDebugString(now) + ", getAuthToken"
2884 + ", " + account
2885 + ", authTokenType " + authTokenType
2886 + ", loginOptions " + loginOptions
2887 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2888 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002889
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002890 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002891 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002892 // If the caller doesn't have permission then create and return the
2893 // "grant permission" intent instead of the "getAuthToken" intent.
2894 if (!permissionGranted) {
2895 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2896 } else {
2897 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2898 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002899 }
2900
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002901 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002902 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002903 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002904 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002905 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002906 Intent intent = newGrantCredentialsPermissionIntent(
2907 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002908 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002909 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002910 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002911 authTokenType,
2912 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002913 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002914 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002915 onResult(bundle);
2916 return;
2917 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002918 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002919 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002920 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2921 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002922 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002923 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002924 "the type and name should not be empty");
2925 return;
2926 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002927 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002928 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002929 saveAuthTokenToDatabase(
2930 mAccounts,
2931 resultAccount,
2932 authTokenType,
2933 authToken);
2934 }
2935 long expiryMillis = result.getLong(
2936 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2937 if (customTokens
2938 && expiryMillis > System.currentTimeMillis()) {
2939 saveCachedToken(
2940 mAccounts,
2941 account,
2942 callerPkg,
2943 callerPkgSigDigest,
2944 authTokenType,
2945 authToken,
2946 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002947 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002948 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002949
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002950 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002951 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002952 /*
2953 * Make sure that the supplied intent is owned by the authenticator
2954 * giving it to the system. Otherwise a malicious authenticator could
2955 * have users launching arbitrary activities by tricking users to
2956 * interact with malicious notifications.
2957 */
2958 checkKeyIntent(
2959 Binder.getCallingUid(),
2960 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002961 doNotification(
2962 mAccounts,
2963 account,
2964 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002965 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002966 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002967 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002968 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002969 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002970 }.bind();
2971 } finally {
2972 restoreCallingIdentity(identityToken);
2973 }
Fred Quintana60307342009-03-24 22:48:12 -07002974 }
2975
Carlos Valdivia91979be2015-05-22 14:11:35 -07002976 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2977 MessageDigest digester;
2978 try {
2979 digester = MessageDigest.getInstance("SHA-256");
2980 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2981 callerPkg, PackageManager.GET_SIGNATURES);
2982 for (Signature sig : pkgInfo.signatures) {
2983 digester.update(sig.toByteArray());
2984 }
2985 } catch (NoSuchAlgorithmException x) {
2986 Log.wtf(TAG, "SHA-256 should be available", x);
2987 digester = null;
2988 } catch (NameNotFoundException e) {
2989 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2990 digester = null;
2991 }
2992 return (digester == null) ? null : digester.digest();
2993 }
2994
Dianne Hackborn41203752012-08-31 14:05:51 -07002995 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002996 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002997 int uid = intent.getIntExtra(
2998 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2999 String authTokenType = intent.getStringExtra(
3000 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07003001 final String titleAndSubtitle =
3002 mContext.getString(R.string.permission_request_notification_with_subtitle,
3003 account.name);
3004 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07003005 String title = titleAndSubtitle;
3006 String subtitle = "";
3007 if (index > 0) {
3008 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04003009 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07003010 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07003011 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003012 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003013 Notification n =
3014 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3015 .setSmallIcon(android.R.drawable.stat_sys_warning)
3016 .setWhen(0)
3017 .setColor(contextForUser.getColor(
3018 com.android.internal.R.color.system_notification_accent_color))
3019 .setContentTitle(title)
3020 .setContentText(subtitle)
3021 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3022 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
3023 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003024 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003025 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003026 }
3027
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003028 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3029 int uid, AccountAuthenticatorResponse response, String authTokenType,
3030 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003031
3032 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003033
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003034 if (startInNewTask) {
3035 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3036 // Since it was set in Eclair+ we can't change it without breaking apps using
3037 // the intent from a non-Activity context. This is the default behavior.
3038 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3039 }
Chris Wren717a8812017-03-31 15:34:39 -04003040 intent.addCategory(getCredentialPermissionNotificationId(account,
3041 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003042 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003043 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3044 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003045 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003046
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003047 return intent;
3048 }
3049
Chris Wren717a8812017-03-31 15:34:39 -04003050 private NotificationId getCredentialPermissionNotificationId(Account account,
3051 String authTokenType, int uid) {
3052 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003053 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003054 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003055 final Pair<Pair<Account, String>, Integer> key =
3056 new Pair<Pair<Account, String>, Integer>(
3057 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04003058 nId = accounts.credentialsPermissionNotificationIds.get(key);
3059 if (nId == null) {
3060 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3061 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
3062 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3063 nId = new NotificationId(tag, id);
3064 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003065 }
3066 }
Chris Wren717a8812017-03-31 15:34:39 -04003067 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003068 }
3069
Chris Wren717a8812017-03-31 15:34:39 -04003070 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3071 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08003072 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04003073 nId = accounts.signinRequiredNotificationIds.get(account);
3074 if (nId == null) {
3075 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3076 + ":" + account.hashCode();
3077 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3078 nId = new NotificationId(tag, id);
3079 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003080 }
3081 }
Chris Wren717a8812017-03-31 15:34:39 -04003082 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003083 }
3084
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003085 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07003086 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003087 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003088 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003089 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003090 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3091 Log.v(TAG, "addAccount: accountType " + accountType
3092 + ", response " + response
3093 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003094 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003095 + ", expectActivityLaunch " + expectActivityLaunch
3096 + ", caller's uid " + Binder.getCallingUid()
3097 + ", pid " + Binder.getCallingPid());
3098 }
Fred Quintana382601f2010-03-25 12:25:10 -07003099 if (response == null) throw new IllegalArgumentException("response is null");
3100 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003101
Amith Yamasani71e6c692013-03-24 17:39:28 -07003102 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003103 final int uid = Binder.getCallingUid();
3104 final int userId = UserHandle.getUserId(uid);
3105 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003106 try {
3107 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3108 "User is not allowed to add an account!");
3109 } catch (RemoteException re) {
3110 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003111 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003112 return;
3113 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003114 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003115 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003116 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3117 "User cannot modify accounts of this type (policy).");
3118 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003119 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003120 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3121 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003122 return;
3123 }
3124
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003125 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003126 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3127 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3128 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3129
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003130 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003131 long identityToken = clearCallingIdentity();
3132 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003133 UserAccounts accounts = getUserAccounts(usrId);
3134 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003135 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3136 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003137 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003138 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003139 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003140 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003141 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003142 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003143 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003144 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003145
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003146 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003147 protected String toDebugString(long now) {
3148 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003149 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003150 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003151 }
3152 }.bind();
3153 } finally {
3154 restoreCallingIdentity(identityToken);
3155 }
Fred Quintana60307342009-03-24 22:48:12 -07003156 }
3157
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003158 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003159 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3160 final String authTokenType, final String[] requiredFeatures,
3161 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003162 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003163 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003164 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3165 Log.v(TAG, "addAccount: accountType " + accountType
3166 + ", response " + response
3167 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003168 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003169 + ", expectActivityLaunch " + expectActivityLaunch
3170 + ", caller's uid " + Binder.getCallingUid()
3171 + ", pid " + Binder.getCallingPid()
3172 + ", for user id " + userId);
3173 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003174 Preconditions.checkArgument(response != null, "response cannot be null");
3175 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003176 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003177 if (isCrossUser(callingUid, userId)) {
3178 throw new SecurityException(
3179 String.format(
3180 "User %s trying to add account for %s" ,
3181 UserHandle.getCallingUserId(),
3182 userId));
3183 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003184
3185 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003186 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003187 try {
3188 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3189 "User is not allowed to add an account!");
3190 } catch (RemoteException re) {
3191 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003192 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003193 return;
3194 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003195 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003196 try {
3197 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3198 "User cannot modify accounts of this type (policy).");
3199 } catch (RemoteException re) {
3200 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003201 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3202 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003203 return;
3204 }
3205
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003206 final int pid = Binder.getCallingPid();
3207 final int uid = Binder.getCallingUid();
3208 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3209 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3210 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3211
3212 long identityToken = clearCallingIdentity();
3213 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003214 UserAccounts accounts = getUserAccounts(userId);
3215 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003216 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3217 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003218 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003219 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003220 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003221 @Override
3222 public void run() throws RemoteException {
3223 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3224 options);
3225 }
3226
3227 @Override
3228 protected String toDebugString(long now) {
3229 return super.toDebugString(now) + ", addAccount"
3230 + ", accountType " + accountType
3231 + ", requiredFeatures "
3232 + (requiredFeatures != null
3233 ? TextUtils.join(",", requiredFeatures)
3234 : null);
3235 }
3236 }.bind();
3237 } finally {
3238 restoreCallingIdentity(identityToken);
3239 }
3240 }
3241
Sandra Kwan78812282015-11-04 11:19:47 -08003242 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003243 public void startAddAccountSession(
3244 final IAccountManagerResponse response,
3245 final String accountType,
3246 final String authTokenType,
3247 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003248 final boolean expectActivityLaunch,
3249 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003250 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003251 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3252 Log.v(TAG,
3253 "startAddAccountSession: accountType " + accountType
3254 + ", response " + response
3255 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003256 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003257 + ", expectActivityLaunch " + expectActivityLaunch
3258 + ", caller's uid " + Binder.getCallingUid()
3259 + ", pid " + Binder.getCallingPid());
3260 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003261 Preconditions.checkArgument(response != null, "response cannot be null");
3262 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003263
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003264 final int uid = Binder.getCallingUid();
3265 final int userId = UserHandle.getUserId(uid);
3266 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003267 try {
3268 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3269 "User is not allowed to add an account!");
3270 } catch (RemoteException re) {
3271 }
3272 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3273 return;
3274 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003275 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003276 try {
3277 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3278 "User cannot modify accounts of this type (policy).");
3279 } catch (RemoteException re) {
3280 }
3281 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3282 userId);
3283 return;
3284 }
Sandra Kwan78812282015-11-04 11:19:47 -08003285 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003286 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3287 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3288 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3289
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003290 // Check to see if the Password should be included to the caller.
3291 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3292 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003293 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003294
Sandra Kwan78812282015-11-04 11:19:47 -08003295 long identityToken = clearCallingIdentity();
3296 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003297 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003298 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3299 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003300 new StartAccountSession(
3301 accounts,
3302 response,
3303 accountType,
3304 expectActivityLaunch,
3305 null /* accountName */,
3306 false /* authDetailsRequired */,
3307 true /* updateLastAuthenticationTime */,
3308 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003309 @Override
3310 public void run() throws RemoteException {
3311 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3312 requiredFeatures, options);
3313 }
3314
3315 @Override
3316 protected String toDebugString(long now) {
3317 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3318 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3319 + accountType + ", requiredFeatures "
3320 + (requiredFeatures != null ? requiredFeaturesStr : null);
3321 }
3322 }.bind();
3323 } finally {
3324 restoreCallingIdentity(identityToken);
3325 }
3326 }
3327
3328 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3329 private abstract class StartAccountSession extends Session {
3330
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003331 private final boolean mIsPasswordForwardingAllowed;
3332
3333 public StartAccountSession(
3334 UserAccounts accounts,
3335 IAccountManagerResponse response,
3336 String accountType,
3337 boolean expectActivityLaunch,
3338 String accountName,
3339 boolean authDetailsRequired,
3340 boolean updateLastAuthenticationTime,
3341 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003342 super(accounts, response, accountType, expectActivityLaunch,
3343 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3344 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003345 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003346 }
3347
3348 @Override
3349 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003350 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003351 mNumResults++;
3352 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003353 if (result != null
3354 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003355 checkKeyIntent(
3356 Binder.getCallingUid(),
3357 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003358 }
Sandra Kwan78812282015-11-04 11:19:47 -08003359 IAccountManagerResponse response;
3360 if (mExpectActivityLaunch && result != null
3361 && result.containsKey(AccountManager.KEY_INTENT)) {
3362 response = mResponse;
3363 } else {
3364 response = getResponseAndClose();
3365 }
3366 if (response == null) {
3367 return;
3368 }
3369 if (result == null) {
3370 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3371 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3372 + response);
3373 }
3374 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3375 "null bundle returned");
3376 return;
3377 }
3378
3379 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3380 // All AccountManager error codes are greater
3381 // than 0
3382 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3383 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3384 return;
3385 }
3386
Hongming Jin368aa192016-07-29 14:29:54 -07003387 // Omit passwords if the caller isn't permitted to see them.
3388 if (!mIsPasswordForwardingAllowed) {
3389 result.remove(AccountManager.KEY_PASSWORD);
3390 }
3391
Sandra Kwan78812282015-11-04 11:19:47 -08003392 // Strip auth token from result.
3393 result.remove(AccountManager.KEY_AUTHTOKEN);
3394
3395 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3396 Log.v(TAG,
3397 getClass().getSimpleName() + " calling onResult() on response " + response);
3398 }
3399
3400 // Get the session bundle created by authenticator. The
3401 // bundle contains data necessary for finishing the session
3402 // later. The session bundle will be encrypted here and
3403 // decrypted later when trying to finish the session.
3404 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3405 if (sessionBundle != null) {
3406 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3407 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003408 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003409 Log.w(TAG, "Account type in session bundle doesn't match request.");
3410 }
3411 // Add accountType info to session bundle. This will
3412 // override any value set by authenticator.
3413 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3414
3415 // Encrypt session bundle before returning to caller.
3416 try {
3417 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3418 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3419 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3420 } catch (GeneralSecurityException e) {
3421 if (Log.isLoggable(TAG, Log.DEBUG)) {
3422 Log.v(TAG, "Failed to encrypt session bundle!", e);
3423 }
3424 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3425 "failed to encrypt session bundle");
3426 return;
3427 }
3428 }
3429
3430 sendResponse(response, result);
3431 }
3432 }
3433
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003434 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003435 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003436 @NonNull Bundle sessionBundle,
3437 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003438 Bundle appInfo,
3439 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003440 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003441 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003442 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3443 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003444 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003445 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003446 + ", caller's uid " + callingUid
3447 + ", caller's user id " + UserHandle.getCallingUserId()
3448 + ", pid " + Binder.getCallingPid()
3449 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003450 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003451 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003452 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3453 // Account type is added to it before encryption.
3454 if (sessionBundle == null || sessionBundle.size() == 0) {
3455 throw new IllegalArgumentException("sessionBundle is empty");
3456 }
3457
Dmitry Dementyev52745472016-12-02 10:27:45 -08003458 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003459 if (isCrossUser(callingUid, userId)) {
3460 throw new SecurityException(
3461 String.format(
3462 "User %s trying to finish session for %s without cross user permission",
3463 UserHandle.getCallingUserId(),
3464 userId));
3465 }
3466
Sandra Kwan0b84b452016-01-20 15:25:42 -08003467 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003468 sendErrorResponse(response,
3469 AccountManager.ERROR_CODE_USER_RESTRICTED,
3470 "User is not allowed to add an account!");
3471 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3472 return;
3473 }
3474
3475 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003476 final Bundle decryptedBundle;
3477 final String accountType;
3478 // First decrypt session bundle to get account type for checking permission.
3479 try {
3480 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3481 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3482 if (decryptedBundle == null) {
3483 sendErrorResponse(
3484 response,
3485 AccountManager.ERROR_CODE_BAD_REQUEST,
3486 "failed to decrypt session bundle");
3487 return;
3488 }
3489 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3490 // Account type cannot be null. This should not happen if session bundle was created
3491 // properly by #StartAccountSession.
3492 if (TextUtils.isEmpty(accountType)) {
3493 sendErrorResponse(
3494 response,
3495 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3496 "accountType is empty");
3497 return;
3498 }
3499
3500 // If by any chances, decryptedBundle contains colliding keys with
3501 // system info
3502 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3503 // update credentials flow, we should replace with the new values of the current call.
3504 if (appInfo != null) {
3505 decryptedBundle.putAll(appInfo);
3506 }
3507
3508 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003509 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003510 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3511 } catch (GeneralSecurityException e) {
3512 if (Log.isLoggable(TAG, Log.DEBUG)) {
3513 Log.v(TAG, "Failed to decrypt session bundle!", e);
3514 }
3515 sendErrorResponse(
3516 response,
3517 AccountManager.ERROR_CODE_BAD_REQUEST,
3518 "failed to decrypt session bundle");
3519 return;
3520 }
3521
Sandra Kwan0b84b452016-01-20 15:25:42 -08003522 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003523 sendErrorResponse(
3524 response,
3525 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3526 "User cannot modify accounts of this type (policy).");
3527 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3528 userId);
3529 return;
3530 }
3531
3532 long identityToken = clearCallingIdentity();
3533 try {
3534 UserAccounts accounts = getUserAccounts(userId);
3535 logRecordWithUid(
3536 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003537 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3538 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003539 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003540 new Session(
3541 accounts,
3542 response,
3543 accountType,
3544 expectActivityLaunch,
3545 true /* stripAuthTokenFromResult */,
3546 null /* accountName */,
3547 false /* authDetailsRequired */,
3548 true /* updateLastAuthenticationTime */) {
3549 @Override
3550 public void run() throws RemoteException {
3551 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3552 }
3553
3554 @Override
3555 protected String toDebugString(long now) {
3556 return super.toDebugString(now)
3557 + ", finishSession"
3558 + ", accountType " + accountType;
3559 }
3560 }.bind();
3561 } finally {
3562 restoreCallingIdentity(identityToken);
3563 }
3564 }
3565
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003566 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003567 final DevicePolicyManagerInternal dpmi =
3568 LocalServices.getService(DevicePolicyManagerInternal.class);
3569 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003570 if (dpmi == null) {
3571 intent = getDefaultCantAddAccountIntent(errorCode);
3572 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003573 intent = dpmi.createUserRestrictionSupportIntent(userId,
3574 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3575 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3576 intent = dpmi.createShowAdminSupportIntent(userId, false);
3577 }
3578 if (intent == null) {
3579 intent = getDefaultCantAddAccountIntent(errorCode);
3580 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003581 long identityToken = clearCallingIdentity();
3582 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003583 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003584 } finally {
3585 restoreCallingIdentity(identityToken);
3586 }
3587 }
3588
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003589 /**
3590 * Called when we don't know precisely who is preventing us from adding an account.
3591 */
3592 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3593 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3594 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3595 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3596 return cantAddAccount;
3597 }
3598
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003599 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003600 public void confirmCredentialsAsUser(
3601 IAccountManagerResponse response,
3602 final Account account,
3603 final Bundle options,
3604 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003605 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003606 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003607 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003608 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3609 Log.v(TAG, "confirmCredentials: " + account
3610 + ", response " + response
3611 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003612 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003613 + ", pid " + Binder.getCallingPid());
3614 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003615 // Only allow the system process to read accounts of other users
3616 if (isCrossUser(callingUid, userId)) {
3617 throw new SecurityException(
3618 String.format(
3619 "User %s trying to confirm account credentials for %s" ,
3620 UserHandle.getCallingUserId(),
3621 userId));
3622 }
Fred Quintana382601f2010-03-25 12:25:10 -07003623 if (response == null) throw new IllegalArgumentException("response is null");
3624 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003625 long identityToken = clearCallingIdentity();
3626 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003627 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003628 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003629 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003630 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003631 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003632 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003633 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003634 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003635 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003636 protected String toDebugString(long now) {
3637 return super.toDebugString(now) + ", confirmCredentials"
3638 + ", " + account;
3639 }
3640 }.bind();
3641 } finally {
3642 restoreCallingIdentity(identityToken);
3643 }
Fred Quintana60307342009-03-24 22:48:12 -07003644 }
3645
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003646 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003647 public void updateCredentials(IAccountManagerResponse response, final Account account,
3648 final String authTokenType, final boolean expectActivityLaunch,
3649 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003650 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003651 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3652 Log.v(TAG, "updateCredentials: " + account
3653 + ", response " + response
3654 + ", authTokenType " + authTokenType
3655 + ", expectActivityLaunch " + expectActivityLaunch
3656 + ", caller's uid " + Binder.getCallingUid()
3657 + ", pid " + Binder.getCallingPid());
3658 }
Fred Quintana382601f2010-03-25 12:25:10 -07003659 if (response == null) throw new IllegalArgumentException("response is null");
3660 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003661 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003662 long identityToken = clearCallingIdentity();
3663 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003664 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003665 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003666 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003667 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003668 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003669 public void run() throws RemoteException {
3670 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3671 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003672 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003673 protected String toDebugString(long now) {
3674 if (loginOptions != null) loginOptions.keySet();
3675 return super.toDebugString(now) + ", updateCredentials"
3676 + ", " + account
3677 + ", authTokenType " + authTokenType
3678 + ", loginOptions " + loginOptions;
3679 }
3680 }.bind();
3681 } finally {
3682 restoreCallingIdentity(identityToken);
3683 }
Fred Quintana60307342009-03-24 22:48:12 -07003684 }
3685
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003686 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003687 public void startUpdateCredentialsSession(
3688 IAccountManagerResponse response,
3689 final Account account,
3690 final String authTokenType,
3691 final boolean expectActivityLaunch,
3692 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003693 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003694 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3695 Log.v(TAG,
3696 "startUpdateCredentialsSession: " + account + ", response " + response
3697 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3698 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3699 + ", pid " + Binder.getCallingPid());
3700 }
3701 if (response == null) {
3702 throw new IllegalArgumentException("response is null");
3703 }
3704 if (account == null) {
3705 throw new IllegalArgumentException("account is null");
3706 }
Sandra Kwana578d112015-12-16 16:01:43 -08003707
3708 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003709 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003710
3711 // Check to see if the Password should be included to the caller.
3712 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3713 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003714 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003715
Sandra Kwane68c37e2015-11-12 17:11:49 -08003716 long identityToken = clearCallingIdentity();
3717 try {
3718 UserAccounts accounts = getUserAccounts(userId);
3719 new StartAccountSession(
3720 accounts,
3721 response,
3722 account.type,
3723 expectActivityLaunch,
3724 account.name,
3725 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003726 true /* updateLastCredentialTime */,
3727 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003728 @Override
3729 public void run() throws RemoteException {
3730 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3731 loginOptions);
3732 }
3733
3734 @Override
3735 protected String toDebugString(long now) {
3736 if (loginOptions != null)
3737 loginOptions.keySet();
3738 return super.toDebugString(now)
3739 + ", startUpdateCredentialsSession"
3740 + ", " + account
3741 + ", authTokenType " + authTokenType
3742 + ", loginOptions " + loginOptions;
3743 }
3744 }.bind();
3745 } finally {
3746 restoreCallingIdentity(identityToken);
3747 }
3748 }
3749
3750 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003751 public void isCredentialsUpdateSuggested(
3752 IAccountManagerResponse response,
3753 final Account account,
3754 final String statusToken) {
3755 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3756 Log.v(TAG,
3757 "isCredentialsUpdateSuggested: " + account + ", response " + response
3758 + ", caller's uid " + Binder.getCallingUid()
3759 + ", pid " + Binder.getCallingPid());
3760 }
3761 if (response == null) {
3762 throw new IllegalArgumentException("response is null");
3763 }
3764 if (account == null) {
3765 throw new IllegalArgumentException("account is null");
3766 }
3767 if (TextUtils.isEmpty(statusToken)) {
3768 throw new IllegalArgumentException("status token is empty");
3769 }
3770
Sandra Kwan390c9d22016-01-12 14:13:37 -08003771 int usrId = UserHandle.getCallingUserId();
3772 long identityToken = clearCallingIdentity();
3773 try {
3774 UserAccounts accounts = getUserAccounts(usrId);
3775 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3776 false /* stripAuthTokenFromResult */, account.name,
3777 false /* authDetailsRequired */) {
3778 @Override
3779 protected String toDebugString(long now) {
3780 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3781 + ", " + account;
3782 }
3783
3784 @Override
3785 public void run() throws RemoteException {
3786 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3787 }
3788
3789 @Override
3790 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003791 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003792 IAccountManagerResponse response = getResponseAndClose();
3793 if (response == null) {
3794 return;
3795 }
3796
3797 if (result == null) {
3798 sendErrorResponse(
3799 response,
3800 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3801 "null bundle");
3802 return;
3803 }
3804
3805 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3806 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3807 + response);
3808 }
3809 // Check to see if an error occurred. We know if an error occurred because all
3810 // error codes are greater than 0.
3811 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3812 sendErrorResponse(response,
3813 result.getInt(AccountManager.KEY_ERROR_CODE),
3814 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3815 return;
3816 }
3817 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3818 sendErrorResponse(
3819 response,
3820 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3821 "no result in response");
3822 return;
3823 }
3824 final Bundle newResult = new Bundle();
3825 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3826 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3827 sendResponse(response, newResult);
3828 }
3829 }.bind();
3830 } finally {
3831 restoreCallingIdentity(identityToken);
3832 }
3833 }
3834
3835 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003836 public void editProperties(IAccountManagerResponse response, final String accountType,
3837 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003838 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003839 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3840 Log.v(TAG, "editProperties: accountType " + accountType
3841 + ", response " + response
3842 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003843 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003844 + ", pid " + Binder.getCallingPid());
3845 }
Fred Quintana382601f2010-03-25 12:25:10 -07003846 if (response == null) throw new IllegalArgumentException("response is null");
3847 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003848 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003849 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3850 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003851 String msg = String.format(
3852 "uid %s cannot edit authenticator properites for account type: %s",
3853 callingUid,
3854 accountType);
3855 throw new SecurityException(msg);
3856 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003857 long identityToken = clearCallingIdentity();
3858 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003859 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003860 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003861 true /* stripAuthTokenFromResult */, null /* accountName */,
3862 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003863 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003864 public void run() throws RemoteException {
3865 mAuthenticator.editProperties(this, mAccountType);
3866 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003867 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003868 protected String toDebugString(long now) {
3869 return super.toDebugString(now) + ", editProperties"
3870 + ", accountType " + accountType;
3871 }
3872 }.bind();
3873 } finally {
3874 restoreCallingIdentity(identityToken);
3875 }
Fred Quintana60307342009-03-24 22:48:12 -07003876 }
3877
Amith Yamasani12747872015-12-07 14:19:49 -08003878 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003879 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3880 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003881 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003882 throw new SecurityException("Can be called only by system UID");
3883 }
3884 Preconditions.checkNotNull(account, "account cannot be null");
3885 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3886 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3887
3888 final int userId = userHandle.getIdentifier();
3889
3890 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3891
3892 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003893 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003894 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003895 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003896 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003897 return false;
3898 }
3899 }
3900
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003901 // Returns package with oldest target SDK for given UID.
3902 private String getPackageNameForUid(int uid) {
3903 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3904 if (ArrayUtils.isEmpty(packageNames)) {
3905 return null;
3906 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003907 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003908 if (packageNames.length == 1) {
3909 return packageName;
3910 }
3911 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003912 int oldestVersion = Integer.MAX_VALUE;
3913 for (String name : packageNames) {
3914 try {
3915 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3916 if (applicationInfo != null) {
3917 int version = applicationInfo.targetSdkVersion;
3918 if (version < oldestVersion) {
3919 oldestVersion = version;
3920 packageName = name;
3921 }
3922 }
3923 } catch (NameNotFoundException e) {
3924 // skip
3925 }
3926 }
3927 return packageName;
3928 }
3929
Svet Ganovf6d424f12016-09-20 20:18:53 -07003930 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3931 int uid) {
3932 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003933 packageName = getPackageNameForUid(uid);
3934 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003935 return false;
3936 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003937 }
3938
3939 // Use null token which means any token. Having a token means the package
3940 // is trusted by the authenticator, hence it is fine to access the account.
3941 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3942 return true;
3943 }
3944 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003945 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003946
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003947 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003948 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003949 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003950 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003951 }
3952
3953 @Override
3954 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3955 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003956 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003957 throw new SecurityException("Can be called only by system UID");
3958 }
3959
3960 Preconditions.checkNotNull(account, "account cannot be null");
3961 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3962 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3963
3964 final int userId = userHandle.getIdentifier();
3965
3966 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3967
3968 final int uid;
3969 try {
3970 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3971 } catch (NameNotFoundException e) {
3972 Slog.e(TAG, "Unknown package " + packageName);
3973 return null;
3974 }
3975
3976 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3977
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003978 final long identity = Binder.clearCallingIdentity();
3979 try {
3980 return PendingIntent.getActivityAsUser(
3981 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3982 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3983 null, new UserHandle(userId)).getIntentSender();
3984 } finally {
3985 Binder.restoreCallingIdentity(identity);
3986 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003987 }
3988
3989 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3990 int uid, RemoteCallback callback) {
3991 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3992 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3993 @Override
3994 public void onResult(Bundle value) throws RemoteException {
3995 handleAuthenticatorResponse(true);
3996 }
3997
3998 @Override
3999 public void onRequestContinued() {
4000 /* ignore */
4001 }
4002
4003 @Override
4004 public void onError(int errorCode, String errorMessage) throws RemoteException {
4005 handleAuthenticatorResponse(false);
4006 }
4007
4008 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4009 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07004010 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004011 UserHandle.getUserHandleForUid(uid));
4012 if (callback != null) {
4013 Bundle result = new Bundle();
4014 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4015 callback.sendResult(result);
4016 }
4017 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07004018 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004019 }
4020
4021 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08004022 public boolean someUserHasAccount(@NonNull final Account account) {
4023 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4024 throw new SecurityException("Only system can check for accounts across users");
4025 }
4026 final long token = Binder.clearCallingIdentity();
4027 try {
4028 AccountAndUser[] allAccounts = getAllAccounts();
4029 for (int i = allAccounts.length - 1; i >= 0; i--) {
4030 if (allAccounts[i].account.equals(account)) {
4031 return true;
4032 }
4033 }
4034 return false;
4035 } finally {
4036 Binder.restoreCallingIdentity(token);
4037 }
4038 }
4039
Fred Quintana33269202009-04-20 16:05:10 -07004040 private class GetAccountsByTypeAndFeatureSession extends Session {
4041 private final String[] mFeatures;
4042 private volatile Account[] mAccountsOfType = null;
4043 private volatile ArrayList<Account> mAccountsWithFeatures = null;
4044 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004045 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004046 private final String mPackageName;
sunjianf29d5492017-05-11 15:42:31 -07004047 private final boolean mIncludeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004048
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004049 public GetAccountsByTypeAndFeatureSession(
4050 UserAccounts accounts,
4051 IAccountManagerResponse response,
4052 String type,
4053 String[] features,
4054 int callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004055 String packageName,
4056 boolean includeManagedNotVisible) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004057 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004058 true /* stripAuthTokenFromResult */, null /* accountName */,
4059 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004060 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07004061 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004062 mPackageName = packageName;
sunjianf29d5492017-05-11 15:42:31 -07004063 mIncludeManagedNotVisible = includeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004064 }
4065
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004066 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004067 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004068 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
sunjianf29d5492017-05-11 15:42:31 -07004069 mCallingUid, mPackageName, mIncludeManagedNotVisible);
Fred Quintana33269202009-04-20 16:05:10 -07004070 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07004071 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07004072 mCurrentAccount = 0;
4073
4074 checkAccount();
4075 }
4076
4077 public void checkAccount() {
4078 if (mCurrentAccount >= mAccountsOfType.length) {
4079 sendResult();
4080 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07004081 }
Fred Quintana33269202009-04-20 16:05:10 -07004082
Fred Quintana29e94b82010-03-10 12:11:51 -08004083 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4084 if (accountAuthenticator == null) {
4085 // It is possible that the authenticator has died, which is indicated by
4086 // mAuthenticator being set to null. If this happens then just abort.
4087 // There is no need to send back a result or error in this case since
4088 // that already happened when mAuthenticator was cleared.
4089 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4090 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4091 + " connected to the authenticator, " + toDebugString());
4092 }
4093 return;
4094 }
Fred Quintana33269202009-04-20 16:05:10 -07004095 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004096 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004097 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004098 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004099 }
4100 }
4101
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004102 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004103 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004104 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004105 mNumResults++;
4106 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004107 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004108 return;
4109 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004110 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004111 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4112 }
4113 mCurrentAccount++;
4114 checkAccount();
4115 }
4116
4117 public void sendResult() {
4118 IAccountManagerResponse response = getResponseAndClose();
4119 if (response != null) {
4120 try {
4121 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4122 for (int i = 0; i < accounts.length; i++) {
4123 accounts[i] = mAccountsWithFeatures.get(i);
4124 }
Fred Quintana56285a62010-12-02 14:20:51 -08004125 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4126 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4127 + response);
4128 }
Fred Quintana33269202009-04-20 16:05:10 -07004129 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004130 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004131 response.onResult(result);
4132 } catch (RemoteException e) {
4133 // if the caller is dead then there is no one to care about remote exceptions
4134 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4135 Log.v(TAG, "failure while notifying response", e);
4136 }
4137 }
4138 }
4139 }
4140
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004141 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004142 protected String toDebugString(long now) {
4143 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4144 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4145 }
4146 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004147
Amith Yamasani04e0d262012-02-14 11:50:53 -08004148 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004149 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004150 * @hide
4151 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004152 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004153 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004154 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004155 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004156 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4157 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004158 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004159 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004160 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004161 long identityToken = clearCallingIdentity();
4162 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004163 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004164 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004165 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004166 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004167 opPackageName,
4168 visibleAccountTypes,
4169 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004170 } finally {
4171 restoreCallingIdentity(identityToken);
4172 }
4173 }
4174
Amith Yamasanif29f2362012-04-05 18:29:52 -07004175 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004176 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004177 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004178 * @hide
4179 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004180 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004181 public AccountAndUser[] getRunningAccounts() {
4182 final int[] runningUserIds;
4183 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004184 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004185 } catch (RemoteException e) {
4186 // Running in system_server; should never happen
4187 throw new RuntimeException(e);
4188 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004189 return getAccounts(runningUserIds);
4190 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004191
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004192 /**
4193 * Returns accounts for all users, ignores visibility values.
4194 *
4195 * @hide
4196 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004197 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004198 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004199 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004200 final int[] userIds = new int[users.size()];
4201 for (int i = 0; i < userIds.length; i++) {
4202 userIds[i] = users.get(i).id;
4203 }
4204 return getAccounts(userIds);
4205 }
4206
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004207 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004208 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004209 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004210 for (int userId : userIds) {
4211 UserAccounts userAccounts = getUserAccounts(userId);
4212 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004213 Account[] accounts = getAccountsFromCache(
4214 userAccounts,
4215 null /* type */,
4216 Binder.getCallingUid(),
4217 null /* packageName */,
4218 false /* include managed not visible*/);
4219 for (Account account : accounts) {
4220 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004221 }
4222 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004223
4224 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4225 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004226 }
4227
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004228 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004229 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004230 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004231 int callingUid = Binder.getCallingUid();
4232 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004233 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004234 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004235 }
4236
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004237 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004238 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004239 String type,
4240 int userId,
4241 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004242 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004243 String opPackageName,
4244 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004245 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004246 // Only allow the system process to read accounts of other users
4247 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004248 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004249 && mContext.checkCallingOrSelfPermission(
4250 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4251 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004252 throw new SecurityException("User " + UserHandle.getCallingUserId()
4253 + " trying to get account for " + userId);
4254 }
4255
Fred Quintana56285a62010-12-02 14:20:51 -08004256 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4257 Log.v(TAG, "getAccounts: accountType " + type
4258 + ", caller's uid " + Binder.getCallingUid()
4259 + ", pid " + Binder.getCallingPid());
4260 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004261
4262 // If the original calling app was using account choosing activity
4263 // provided by the framework or authenticator we'll passing in
4264 // the original caller's uid here, which is what should be used for filtering.
4265 List<String> managedTypes =
4266 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4267 if (packageUid != -1 &&
4268 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4269 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004270 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004271 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004272 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004273 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4274 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004275 if (visibleAccountTypes.isEmpty()
4276 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004277 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004278 } else if (visibleAccountTypes.contains(type)) {
4279 // Prune the list down to just the requested type.
4280 visibleAccountTypes = new ArrayList<>();
4281 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004282 } // else aggregate all the visible accounts (it won't matter if the
4283 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004284
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004285 long identityToken = clearCallingIdentity();
4286 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004287 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004288 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004289 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004290 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004291 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004292 visibleAccountTypes,
4293 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004294 } finally {
4295 restoreCallingIdentity(identityToken);
4296 }
4297 }
4298
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004299 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004300 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004301 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004302 int callingUid,
4303 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004304 List<String> visibleAccountTypes,
4305 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004306 ArrayList<Account> visibleAccounts = new ArrayList<>();
4307 for (String visibleType : visibleAccountTypes) {
4308 Account[] accountsForType = getAccountsFromCache(
4309 userAccounts, visibleType, callingUid, callingPackage,
4310 includeUserManagedNotVisible);
4311 if (accountsForType != null) {
4312 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004313 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004314 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004315 Account[] result = new Account[visibleAccounts.size()];
4316 for (int i = 0; i < visibleAccounts.size(); i++) {
4317 result[i] = visibleAccounts.get(i);
4318 }
4319 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004320 }
4321
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004322 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004323 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4324 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004325 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004326 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004327 for (Account account : accounts) {
4328 addSharedAccountAsUser(account, userId);
4329 }
4330 }
4331
4332 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004333 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004334 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004335 accounts.accountsDb.deleteSharedAccount(account);
4336 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004337 if (accountId < 0) {
4338 Log.w(TAG, "insertAccountIntoDatabase: " + account
4339 + ", skipping the DB insert failed");
4340 return false;
4341 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004342 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4343 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004344 return true;
4345 }
4346
4347 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004348 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4349 userId = handleIncomingUser(userId);
4350 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004351 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4352 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004353 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004354 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004355 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004356 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004357 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004358 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004359 }
4360 return r > 0;
4361 }
4362
4363 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004364 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004365 return removeSharedAccountAsUser(account, userId, getCallingUid());
4366 }
4367
4368 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004369 userId = handleIncomingUser(userId);
4370 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004371 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4372 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004373 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004374 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004375 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004376 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004377 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004378 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004379 }
4380
4381 @Override
4382 public Account[] getSharedAccountsAsUser(int userId) {
4383 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004384 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004385 synchronized (accounts.dbLock) {
4386 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4387 Account[] accountArray = new Account[accountList.size()];
4388 accountList.toArray(accountArray);
4389 return accountArray;
4390 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004391 }
4392
4393 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004394 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004395 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004396 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004397 }
4398
Amith Yamasani27db4682013-03-30 17:07:47 -07004399 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004400 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004401 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004402 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004403 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004404 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004405 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4406 + callingUid + " with uid=" + uid);
4407 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004408 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004409 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004410 }
4411
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004412 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004413 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004414 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4415 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004416 int callingUid = Binder.getCallingUid();
4417 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004418 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004419 int packageUid = -1;
4420 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004421 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4422 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004423 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004424 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004425 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004426 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004427 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4428 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004429 }
sunjiand62dc392017-06-01 12:05:59 -07004430 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4431 return getAccountsAsUserForPackage(type, userId,
4432 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4433 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004434 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004435 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004436 }
4437
sunjianf29d5492017-05-11 15:42:31 -07004438 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4439 if (accounts.length < 1) return false;
4440 if (accounts.length > 1) return true;
4441 Account account = accounts[0];
4442 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4443 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4444 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4445 return false;
4446 }
4447
4448 private void startChooseAccountActivityWithAccounts(
sunjianbdabd402017-06-06 17:54:07 -07004449 IAccountManagerResponse response, Account[] accounts, String callingPackage) {
sunjianf29d5492017-05-11 15:42:31 -07004450 Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4451 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4452 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4453 new AccountManagerResponse(response));
sunjianbdabd402017-06-06 17:54:07 -07004454 intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004455
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)) {
sunjianbdabd402017-06-06 17:54:07 -07004465 startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004466 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 {
Jeff Sharkeyd722e782017-06-12 17:33:07 -06004708 intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4709 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4710 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4711 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004712 long bid = Binder.clearCallingIdentity();
4713 try {
4714 PackageManager pm = mContext.getPackageManager();
4715 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4716 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4717 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004718 if (!isExportedSystemActivity(targetActivityInfo)
4719 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4720 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004721 String pkgName = targetActivityInfo.packageName;
4722 String activityName = targetActivityInfo.name;
4723 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4724 + "does not share a signature with the supplying authenticator (%s).";
4725 throw new SecurityException(
4726 String.format(tmpl, activityName, pkgName, mAccountType));
4727 }
4728 } finally {
4729 Binder.restoreCallingIdentity(bid);
4730 }
4731 }
4732
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004733 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4734 String className = activityInfo.name;
4735 return "android".equals(activityInfo.packageName) &&
4736 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4737 || CantAddAccountActivity.class.getName().equals(className));
4738 }
4739
Fred Quintanaa698f422009-04-08 19:14:54 -07004740 private void close() {
4741 synchronized (mSessions) {
4742 if (mSessions.remove(toString()) == null) {
4743 // the session was already closed, so bail out now
4744 return;
4745 }
4746 }
4747 if (mResponse != null) {
4748 // stop listening for response deaths
4749 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4750
4751 // clear this so that we don't accidentally send any further results
4752 mResponse = null;
4753 }
4754 cancelTimeout();
4755 unbind();
4756 }
4757
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004758 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004759 public void binderDied() {
4760 mResponse = null;
4761 close();
4762 }
4763
4764 protected String toDebugString() {
4765 return toDebugString(SystemClock.elapsedRealtime());
4766 }
4767
4768 protected String toDebugString(long now) {
4769 return "Session: expectLaunch " + mExpectActivityLaunch
4770 + ", connected " + (mAuthenticator != null)
4771 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4772 + "/" + mNumErrors + ")"
4773 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4774 }
4775
Fred Quintana60307342009-03-24 22:48:12 -07004776 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004777 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4778 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4779 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004780 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004781 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004782 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004783 }
4784 }
4785
4786 private void unbind() {
4787 if (mAuthenticator != null) {
4788 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004789 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004790 }
4791 }
4792
Fred Quintana60307342009-03-24 22:48:12 -07004793 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004794 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004795 }
4796
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004797 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004798 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004799 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004800 try {
4801 run();
4802 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004803 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004804 "remote exception");
4805 }
Fred Quintana60307342009-03-24 22:48:12 -07004806 }
4807
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004808 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004809 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004810 mAuthenticator = null;
4811 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004812 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004813 try {
4814 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4815 "disconnected");
4816 } catch (RemoteException e) {
4817 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4818 Log.v(TAG, "Session.onServiceDisconnected: "
4819 + "caught RemoteException while responding", e);
4820 }
4821 }
Fred Quintana60307342009-03-24 22:48:12 -07004822 }
4823 }
4824
Fred Quintanab839afc2009-10-14 15:57:28 -07004825 public abstract void run() throws RemoteException;
4826
Fred Quintana60307342009-03-24 22:48:12 -07004827 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004828 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004829 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004830 try {
4831 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4832 "timeout");
4833 } catch (RemoteException e) {
4834 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4835 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4836 e);
4837 }
4838 }
Fred Quintana60307342009-03-24 22:48:12 -07004839 }
4840 }
4841
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004842 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004843 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004844 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004845 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004846 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004847 if (result != null) {
4848 boolean isSuccessfulConfirmCreds = result.getBoolean(
4849 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004850 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004851 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4852 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004853 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004854 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4855 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004856 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004857 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004858 if (needUpdate || mAuthDetailsRequired) {
4859 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4860 if (needUpdate && accountPresent) {
4861 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4862 }
4863 if (mAuthDetailsRequired) {
4864 long lastAuthenticatedTime = -1;
4865 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004866 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004867 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004868 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004869 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004870 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004871 lastAuthenticatedTime);
4872 }
4873 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004874 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004875 if (result != null
4876 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004877 checkKeyIntent(
4878 Binder.getCallingUid(),
4879 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004880 }
4881 if (result != null
4882 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004883 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4884 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004885 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4886 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004887 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4888 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004889 }
Fred Quintana60307342009-03-24 22:48:12 -07004890 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004891 IAccountManagerResponse response;
4892 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004893 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004894 response = mResponse;
4895 } else {
4896 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004897 }
Fred Quintana60307342009-03-24 22:48:12 -07004898 if (response != null) {
4899 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004900 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004901 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4902 Log.v(TAG, getClass().getSimpleName()
4903 + " calling onError() on response " + response);
4904 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004905 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004906 "null bundle returned");
4907 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004908 if (mStripAuthTokenFromResult) {
4909 result.remove(AccountManager.KEY_AUTHTOKEN);
4910 }
Fred Quintana56285a62010-12-02 14:20:51 -08004911 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4912 Log.v(TAG, getClass().getSimpleName()
4913 + " calling onResult() on response " + response);
4914 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004915 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4916 (intent == null)) {
4917 // All AccountManager error codes are greater than 0
4918 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4919 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4920 } else {
4921 response.onResult(result);
4922 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004923 }
Fred Quintana60307342009-03-24 22:48:12 -07004924 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004925 // if the caller is dead then there is no one to care about remote exceptions
4926 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4927 Log.v(TAG, "failure while notifying response", e);
4928 }
Fred Quintana60307342009-03-24 22:48:12 -07004929 }
4930 }
4931 }
Fred Quintana60307342009-03-24 22:48:12 -07004932
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004933 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004934 public void onRequestContinued() {
4935 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004936 }
4937
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004938 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004939 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004940 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004941 IAccountManagerResponse response = getResponseAndClose();
4942 if (response != null) {
4943 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004944 Log.v(TAG, getClass().getSimpleName()
4945 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004946 }
4947 try {
4948 response.onError(errorCode, errorMessage);
4949 } catch (RemoteException e) {
4950 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4951 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4952 }
4953 }
4954 } else {
4955 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4956 Log.v(TAG, "Session.onError: already closed");
4957 }
Fred Quintana60307342009-03-24 22:48:12 -07004958 }
4959 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004960
4961 /**
4962 * find the component name for the authenticator and initiate a bind
4963 * if no authenticator or the bind fails then return false, otherwise return true
4964 */
4965 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004966 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4967 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4968 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004969 if (authenticatorInfo == null) {
4970 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4971 Log.v(TAG, "there is no authenticator for " + authenticatorType
4972 + ", bailing out");
4973 }
4974 return false;
4975 }
4976
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004977 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004978 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004979 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4980 + " which isn't encryption aware");
4981 return false;
4982 }
4983
Fred Quintanab839afc2009-10-14 15:57:28 -07004984 Intent intent = new Intent();
4985 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4986 intent.setComponent(authenticatorInfo.componentName);
4987 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4988 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4989 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004990 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004991 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004992 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4993 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4994 }
4995 return false;
4996 }
4997
Fred Quintanab839afc2009-10-14 15:57:28 -07004998 return true;
4999 }
Fred Quintana60307342009-03-24 22:48:12 -07005000 }
5001
Svet Ganov5d09c992016-09-07 09:57:41 -07005002 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07005003 MessageHandler(Looper looper) {
5004 super(looper);
5005 }
Costin Manolache3348f142009-09-29 18:58:36 -07005006
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07005007 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005008 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07005009 switch (msg.what) {
5010 case MESSAGE_TIMED_OUT:
5011 Session session = (Session)msg.obj;
5012 session.onTimedOut();
5013 break;
5014
Amith Yamasani5be347b2013-03-31 17:44:31 -07005015 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00005016 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07005017 break;
5018
Fred Quintana60307342009-03-24 22:48:12 -07005019 default:
5020 throw new IllegalStateException("unhandled message: " + msg.what);
5021 }
5022 }
5023 }
5024
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005025 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005026 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005027 }
5028
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005029 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005030 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005031 }
5032
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005033 /*
5034 * This function receives an opened writable database.
5035 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005036 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005037 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005038 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005039 }
5040
5041 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005042 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005043 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005044 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005045 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005046
5047 class LogRecordTask implements Runnable {
5048 private final String action;
5049 private final String tableName;
5050 private final long accountId;
5051 private final UserAccounts userAccount;
5052 private final int callingUid;
5053 private final long userDebugDbInsertionPoint;
5054
5055 LogRecordTask(final String action,
5056 final String tableName,
5057 final long accountId,
5058 final UserAccounts userAccount,
5059 final int callingUid,
5060 final long userDebugDbInsertionPoint) {
5061 this.action = action;
5062 this.tableName = tableName;
5063 this.accountId = accountId;
5064 this.userAccount = userAccount;
5065 this.callingUid = callingUid;
5066 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5067 }
5068
Andrew Scullc7770d62017-05-22 17:49:58 +01005069 @Override
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005070 public void run() {
5071 SQLiteStatement logStatement = userAccount.statementForLogging;
5072 logStatement.bindLong(1, accountId);
5073 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005074 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005075 logStatement.bindLong(4, callingUid);
5076 logStatement.bindString(5, tableName);
5077 logStatement.bindLong(6, userDebugDbInsertionPoint);
5078 logStatement.execute();
5079 logStatement.clearBindings();
5080 }
5081 }
5082
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005083 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5084 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005085 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005086 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005087 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005088 }
5089
5090 /*
5091 * This should only be called once to compile the sql statement for logging
5092 * and to find the insertion point.
5093 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005094 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
5095 userAccount.debugDbInsertionPoint = userAccount.accountsDb
5096 .calculateDebugTableInsertionPoint();
5097 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005098 }
5099
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005100 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07005101 return asBinder();
5102 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005103
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005104 /**
5105 * Searches array of arguments for the specified string
5106 * @param args array of argument strings
5107 * @param value value to search for
5108 * @return true if the value is contained in the array
5109 */
5110 private static boolean scanArgs(String[] args, String value) {
5111 if (args != null) {
5112 for (String arg : args) {
5113 if (value.equals(arg)) {
5114 return true;
5115 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005116 }
5117 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005118 return false;
5119 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005120
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005121 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005122 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005123 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005124 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005125 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07005126
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005127 final List<UserInfo> users = getUserManager().getUsers();
5128 for (UserInfo user : users) {
5129 ipw.println("User " + user + ":");
5130 ipw.increaseIndent();
5131 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5132 ipw.println();
5133 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08005134 }
5135 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005136
Amith Yamasani04e0d262012-02-14 11:50:53 -08005137 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5138 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005139 if (isCheckinRequest) {
5140 // This is a checkin request. *Only* upload the account types and the count of
5141 // each.
5142 synchronized (userAccounts.dbLock) {
5143 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5144 }
5145 } else {
5146 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5147 Process.SYSTEM_UID, null /* packageName */, false);
5148 fout.println("Accounts: " + accounts.length);
5149 for (Account account : accounts) {
5150 fout.println(" " + account);
5151 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005152
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005153 // Add debug information.
5154 fout.println();
5155 synchronized (userAccounts.dbLock) {
5156 userAccounts.accountsDb.dumpDebugTable(fout);
5157 }
5158 fout.println();
5159 synchronized (mSessions) {
5160 final long now = SystemClock.elapsedRealtime();
5161 fout.println("Active Sessions: " + mSessions.size());
5162 for (Session session : mSessions.values()) {
5163 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005164 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005165 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005166
5167 fout.println();
5168 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005169 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005170 }
5171
Amith Yamasani04e0d262012-02-14 11:50:53 -08005172 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005173 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005174 long identityToken = clearCallingIdentity();
5175 try {
5176 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5177 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5178 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005179
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005180 if (intent.getComponent() != null &&
5181 GrantCredentialsPermissionActivity.class.getName().equals(
5182 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005183 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005184 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005185 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04005186 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5187 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005188
Fred Quintana33f889a2009-09-14 17:31:26 -07005189 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005190 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05005191 Notification n =
5192 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005193 .setWhen(0)
5194 .setSmallIcon(android.R.drawable.stat_sys_warning)
5195 .setColor(contextForUser.getColor(
5196 com.android.internal.R.color.system_notification_accent_color))
5197 .setContentTitle(String.format(notificationTitleFormat, account.name))
5198 .setContentText(message)
5199 .setContentIntent(PendingIntent.getActivityAsUser(
5200 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005201 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005202 .build();
Chris Wren717a8812017-03-31 15:34:39 -04005203 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005204 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005205 } finally {
5206 restoreCallingIdentity(identityToken);
5207 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005208 }
5209
Chris Wren717a8812017-03-31 15:34:39 -04005210 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005211 String packageName, int userId) {
5212 final long token = clearCallingIdentity();
5213 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005214 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005215 try {
Chris Wren717a8812017-03-31 15:34:39 -04005216 notificationManager.enqueueNotificationWithTag(packageName, packageName,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04005217 id.mTag, id.mId, notification, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005218 } catch (RemoteException e) {
5219 /* ignore - local call */
5220 }
5221 } finally {
5222 Binder.restoreCallingIdentity(token);
5223 }
Fred Quintana56285a62010-12-02 14:20:51 -08005224 }
5225
Chris Wren717a8812017-03-31 15:34:39 -04005226 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005227 cancelNotification(id, mContext.getPackageName(), user);
5228 }
5229
Chris Wren717a8812017-03-31 15:34:39 -04005230 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005231 long identityToken = clearCallingIdentity();
5232 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005233 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04005234 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005235 } catch (RemoteException e) {
5236 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005237 } finally {
5238 restoreCallingIdentity(identityToken);
5239 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005240 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005241
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005242 private boolean isPermittedForPackage(String packageName, int uid, int userId,
5243 String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005244 final long identity = Binder.clearCallingIdentity();
5245 try {
5246 IPackageManager pm = ActivityThread.getPackageManager();
5247 for (String perm : permissions) {
5248 if (pm.checkPermission(perm, packageName, userId)
5249 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005250 // Checks runtime permission revocation.
5251 final int opCode = AppOpsManager.permissionToOpCode(perm);
5252 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5253 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5254 return true;
5255 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005256 }
5257 }
5258 } catch (RemoteException e) {
5259 /* ignore - local call */
5260 } finally {
5261 Binder.restoreCallingIdentity(identity);
5262 }
5263 return false;
5264 }
5265
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005266 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5267 for (String perm : permissions) {
5268 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5269 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5270 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5271 }
5272 final int opCode = AppOpsManager.permissionToOpCode(perm);
5273 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5274 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5275 return true;
5276 }
5277 }
5278 }
5279 return false;
5280 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005281
Amith Yamasani67df64b2012-12-14 12:09:36 -08005282 private int handleIncomingUser(int userId) {
5283 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005284 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005285 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5286 } catch (RemoteException re) {
5287 // Shouldn't happen, local.
5288 }
5289 return userId;
5290 }
5291
Christopher Tateccbf84f2013-05-08 15:25:41 -07005292 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005293 String[] packages;
5294 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005295 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005296 packages = mPackageManager.getPackagesForUid(callingUid);
5297 } finally {
5298 Binder.restoreCallingIdentity(identityToken);
5299 }
5300 if (packages == null) {
5301 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005302 return false;
5303 }
Fred Quintana7be59642009-08-24 18:29:25 -07005304 for (String name : packages) {
5305 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005306 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08005307 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08005308 && (packageInfo.applicationInfo.privateFlags
5309 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07005310 return true;
5311 }
5312 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005313 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07005314 return false;
5315 }
5316 }
5317 return false;
5318 }
5319
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005320 private boolean permissionIsGranted(
5321 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005322 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5323 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5324 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5325 }
5326 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005327 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005328
5329 if (isPrivileged(callerUid)) {
5330 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5331 Log.v(TAG, "Access to " + account + " granted calling uid "
5332 + callerUid + " privileged");
5333 }
5334 return true;
5335 }
5336 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5337 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5338 Log.v(TAG, "Access to " + account + " granted calling uid "
5339 + callerUid + " manages the account");
5340 }
5341 return true;
5342 }
5343 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5344 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5345 Log.v(TAG, "Access to " + account + " granted calling uid "
5346 + callerUid + " user granted access");
5347 }
5348 return true;
5349 }
5350
5351 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5352 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5353 }
5354
5355 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005356 }
5357
Svetoslavf3f02ac2015-09-08 14:36:35 -07005358 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5359 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005360 if (accountType == null) {
5361 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005362 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005363 return getTypesVisibleToCaller(callingUid, userId,
5364 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005365 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005366 }
5367
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005368 // Method checks visibility for applications targeing API level below {@link
5369 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005370 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005371 private boolean checkGetAccountsPermission(String packageName, int uid, int userId) {
5372 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005373 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5374 }
5375
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005376 private boolean checkReadContactsPermission(String packageName, int uid, int userId) {
5377 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS);
5378 }
5379
5380 // Heuristic to check that account type may be associated with some contacts data and
5381 // therefore READ_CONTACTS permission grants the access to account by default.
5382 private boolean accountTypeManagesContacts(String accountType, int userId) {
5383 if (accountType == null) {
5384 return false;
5385 }
5386 long identityToken = Binder.clearCallingIdentity();
5387 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5388 try {
5389 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5390 } finally {
5391 Binder.restoreCallingIdentity(identityToken);
5392 }
5393 // Check contacts related permissions for authenticator.
5394 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5395 : serviceInfos) {
5396 if (accountType.equals(serviceInfo.type.type)) {
5397 return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId,
5398 Manifest.permission.WRITE_CONTACTS);
5399 }
5400 }
5401 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005402 }
5403
5404 /**
5405 * Method checks package uid and signature with Authenticator which manages accountType.
5406 *
5407 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5408 * SIGNATURE_CHECK_MISMATCH otherwise.
5409 */
5410 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5411 if (accountType == null) {
5412 return SIGNATURE_CHECK_MISMATCH;
5413 }
5414
5415 long identityToken = Binder.clearCallingIdentity();
5416 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5417 try {
5418 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5419 } finally {
5420 Binder.restoreCallingIdentity(identityToken);
5421 }
5422 // Check for signature match with Authenticator.
5423 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5424 : serviceInfos) {
5425 if (accountType.equals(serviceInfo.type.type)) {
5426 if (serviceInfo.uid == callingUid) {
5427 return SIGNATURE_CHECK_UID_MATCH;
5428 }
5429 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5430 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5431 return SIGNATURE_CHECK_MATCH;
5432 }
5433 }
5434 }
5435 return SIGNATURE_CHECK_MISMATCH;
5436 }
5437
5438 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005439 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5440 if (accountType == null) {
5441 return false;
5442 } else {
5443 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5444 }
5445 }
5446
Svetoslavf3f02ac2015-09-08 14:36:35 -07005447 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5448 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005449 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005450 }
5451
5452 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005453 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005454 }
5455
5456 private List<String> getTypesForCaller(
5457 int callingUid, int userId, boolean isOtherwisePermitted) {
5458 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005459 long identityToken = Binder.clearCallingIdentity();
5460 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5461 try {
5462 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5463 } finally {
5464 Binder.restoreCallingIdentity(identityToken);
5465 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005466 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005467 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005468 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5469 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005470 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005471 }
5472 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005473 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005474 }
5475
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005476 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5477 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5478 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5479 if (account.name.equals(accountName)) {
5480 return true;
5481 }
5482 }
5483 }
5484 return false;
5485 }
5486
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005487 private static void checkManageUsersPermission(String message) {
5488 if (ActivityManager.checkComponentPermission(
5489 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5490 != PackageManager.PERMISSION_GRANTED) {
5491 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5492 }
5493 }
5494
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005495 private static void checkManageOrCreateUsersPermission(String message) {
5496 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5497 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5498 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5499 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5500 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5501 + message);
5502 }
5503 }
5504
Amith Yamasani04e0d262012-02-14 11:50:53 -08005505 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5506 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005507 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005508 return true;
5509 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005510 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005511 synchronized (accounts.dbLock) {
5512 synchronized (accounts.cacheLock) {
5513 long grantsCount;
5514 if (authTokenType != null) {
5515 grantsCount = accounts.accountsDb
5516 .findMatchingGrantsCount(callerUid, authTokenType, account);
5517 } else {
5518 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5519 account);
5520 }
5521 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005522
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005523 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5524 // TODO: Skip this check when running automated tests. Replace this
5525 // with a more general solution.
5526 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5527 + authTokenType + " by uid " + callerUid
5528 + " but ignoring since device is in test harness.");
5529 return true;
5530 }
5531 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005532 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005533 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005534 }
5535
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005536 private boolean isSystemUid(int callingUid) {
5537 String[] packages = null;
5538 long ident = Binder.clearCallingIdentity();
5539 try {
5540 packages = mPackageManager.getPackagesForUid(callingUid);
5541 } finally {
5542 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005543 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005544 if (packages != null) {
5545 for (String name : packages) {
5546 try {
5547 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5548 if (packageInfo != null
5549 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5550 != 0) {
5551 return true;
5552 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005553 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005554 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5555 }
5556 }
5557 } else {
5558 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005559 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005560 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005561 }
5562
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005563 /** Succeeds if any of the specified permissions are granted. */
5564 private void checkReadAccountsPermitted(
5565 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005566 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005567 int userId,
5568 String opPackageName) {
5569 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005570 String msg = String.format(
5571 "caller uid %s cannot access %s accounts",
5572 callingUid,
5573 accountType);
5574 Log.w(TAG, " " + msg);
5575 throw new SecurityException(msg);
5576 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005577 }
5578
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005579 private boolean canUserModifyAccounts(int userId, int callingUid) {
5580 // the managing app can always modify accounts
5581 if (isProfileOwner(callingUid)) {
5582 return true;
5583 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005584 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5585 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5586 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005587 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005588 return true;
5589 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005590
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005591 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5592 // the managing app can always modify accounts
5593 if (isProfileOwner(callingUid)) {
5594 return true;
5595 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005596 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5597 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005598 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005599 if (typesArray == null) {
5600 return true;
5601 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005602 for (String forbiddenType : typesArray) {
5603 if (forbiddenType.equals(accountType)) {
5604 return false;
5605 }
5606 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005607 return true;
5608 }
5609
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005610 private boolean isProfileOwner(int uid) {
5611 final DevicePolicyManagerInternal dpmi =
5612 LocalServices.getService(DevicePolicyManagerInternal.class);
5613 return (dpmi != null)
5614 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5615 }
5616
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005617 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005618 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5619 throws RemoteException {
5620 final int callingUid = getCallingUid();
5621
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005622 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005623 throw new SecurityException();
5624 }
5625
5626 if (value) {
5627 grantAppPermission(account, authTokenType, uid);
5628 } else {
5629 revokeAppPermission(account, authTokenType, uid);
5630 }
5631 }
5632
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005633 /**
5634 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5635 * <p>
5636 * Although this is public it can only be accessed via the AccountManagerService object
5637 * which is in the system. This means we don't need to protect it with permissions.
5638 * @hide
5639 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005640 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005641 if (account == null || authTokenType == null) {
5642 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005643 return;
5644 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005645 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005646 synchronized (accounts.dbLock) {
5647 synchronized (accounts.cacheLock) {
5648 long accountId = accounts.accountsDb.findDeAccountId(account);
5649 if (accountId >= 0) {
5650 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5651 }
5652 cancelNotification(
5653 getCredentialPermissionNotificationId(account, authTokenType, uid),
5654 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005655
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005656 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5657 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005658 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005659
5660 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5661 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5662 : mAppPermissionChangeListeners) {
5663 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5664 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005665 }
5666
5667 /**
5668 * Don't allow callers with the given uid permission to get credentials for
5669 * account/authTokenType.
5670 * <p>
5671 * Although this is public it can only be accessed via the AccountManagerService object
5672 * which is in the system. This means we don't need to protect it with permissions.
5673 * @hide
5674 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005675 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005676 if (account == null || authTokenType == null) {
5677 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005678 return;
5679 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005680 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005681 synchronized (accounts.dbLock) {
5682 synchronized (accounts.cacheLock) {
5683 accounts.accountsDb.beginTransaction();
5684 try {
5685 long accountId = accounts.accountsDb.findDeAccountId(account);
5686 if (accountId >= 0) {
5687 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5688 accountId, authTokenType, uid);
5689 accounts.accountsDb.setTransactionSuccessful();
5690 }
5691 } finally {
5692 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005693 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005694
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005695 cancelNotification(
5696 getCredentialPermissionNotificationId(account, authTokenType, uid),
5697 UserHandle.of(accounts.userId));
5698 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005699 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005700
5701 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5702 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5703 : mAppPermissionChangeListeners) {
5704 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5705 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005706 }
Fred Quintana56285a62010-12-02 14:20:51 -08005707
Amith Yamasani04e0d262012-02-14 11:50:53 -08005708 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5709 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005710 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005711 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005712 for (Account curAccount : oldAccountsForType) {
5713 if (!curAccount.equals(account)) {
5714 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005715 }
5716 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005717 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005718 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005719 } else {
5720 Account[] newAccountsForType = new Account[newAccountsList.size()];
5721 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005722 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005723 }
Fred Quintana56285a62010-12-02 14:20:51 -08005724 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005725 accounts.userDataCache.remove(account);
5726 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005727 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005728 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005729 }
5730
5731 /**
5732 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005733 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5734 * processes and if you will return this account to apps you should return the result.
5735 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005736 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005737 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005738 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005739 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5740 Account[] newAccountsForType = new Account[oldLength + 1];
5741 if (accountsForType != null) {
5742 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005743 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005744 String token = account.getAccessId() != null ? account.getAccessId()
5745 : UUID.randomUUID().toString();
5746 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005747 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005748 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005749 }
5750
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005751 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005752 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005753 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005754 String visibilityFilterPackage = callingPackage;
5755 if (visibilityFilterPackage == null) {
5756 visibilityFilterPackage = getPackageNameForUid(callingUid);
5757 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005758 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005759 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005760 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005761 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5762 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5763 || (includeManagedNotVisible
5764 && (visibility
5765 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5766 firstPass.put(account, visibility);
5767 }
5768 }
5769 Map<Account, Integer> secondPass =
5770 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5771
5772 Account[] filtered = new Account[secondPass.size()];
5773 filtered = secondPass.keySet().toArray(filtered);
5774 return filtered;
5775 }
5776
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005777 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005778 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005779 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005780 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005781 // first part is to filter shared accounts.
5782 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005783 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005784 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005785 return unfiltered;
5786 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005787 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005788 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005789 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005790 if (packages == null) {
5791 packages = new String[] {};
5792 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005793 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005794 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005795 // This might be a temporary way to specify a visible list
5796 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005797 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5798 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005799 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005800 return unfiltered;
5801 }
5802 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005803 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005804 if (ArrayUtils.isEmpty(sharedAccounts)) {
5805 return unfiltered;
5806 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005807 String requiredAccountType = "";
5808 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005809 // If there's an explicit callingPackage specified, check if that package
5810 // opted in to see restricted accounts.
5811 if (callingPackage != null) {
5812 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005813 if (pi != null && pi.restrictedAccountType != null) {
5814 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005815 }
5816 } else {
5817 // Otherwise check if the callingUid has a package that has opted in
5818 for (String packageName : packages) {
5819 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5820 if (pi != null && pi.restrictedAccountType != null) {
5821 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005822 break;
5823 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005824 }
5825 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005826 } catch (NameNotFoundException e) {
5827 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005828 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005829 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005830 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5831 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005832 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005833 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005834 } else {
5835 boolean found = false;
5836 for (Account shared : sharedAccounts) {
5837 if (shared.equals(account)) {
5838 found = true;
5839 break;
5840 }
5841 }
5842 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005843 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005844 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005845 }
5846 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005847 return filtered;
5848 } else {
5849 return unfiltered;
5850 }
5851 }
5852
Amith Yamasani27db4682013-03-30 17:07:47 -07005853 /*
5854 * packageName can be null. If not null, it should be used to filter out restricted accounts
5855 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005856 *
5857 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5858 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005859 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005860 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005861 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005862 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005863 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5864 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005865 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005866 Account[] accounts;
5867 synchronized (userAccounts.cacheLock) {
5868 accounts = userAccounts.accountCache.get(accountType);
5869 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005870 if (accounts == null) {
5871 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005872 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005873 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5874 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005875 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005876 } else {
5877 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005878 Account[] accountsArray;
5879 synchronized (userAccounts.cacheLock) {
5880 for (Account[] accounts : userAccounts.accountCache.values()) {
5881 totalLength += accounts.length;
5882 }
5883 if (totalLength == 0) {
5884 return EMPTY_ACCOUNT_ARRAY;
5885 }
5886 accountsArray = new Account[totalLength];
5887 totalLength = 0;
5888 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5889 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5890 accountsOfType.length);
5891 totalLength += accountsOfType.length;
5892 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005893 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005894 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005895 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005896 }
5897 }
5898
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005899 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005900 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005901 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005902 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005903 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005904 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005905 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005906 }
5907 if (value == null) {
5908 userDataForAccount.remove(key);
5909 } else {
5910 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005911 }
5912 }
5913
Carlos Valdivia91979be2015-05-22 14:11:35 -07005914 protected String readCachedTokenInternal(
5915 UserAccounts accounts,
5916 Account account,
5917 String tokenType,
5918 String callingPackage,
5919 byte[] pkgSigDigest) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005920 synchronized (accounts.dbLock) {
5921 synchronized (accounts.cacheLock) {
5922 return accounts.accountTokenCaches.get(
5923 account, tokenType, callingPackage, pkgSigDigest);
5924 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07005925 }
5926 }
5927
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005928 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005929 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005930 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005931 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005932 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005933 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005934 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005935 }
5936 if (value == null) {
5937 authTokensForAccount.remove(key);
5938 } else {
5939 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005940 }
5941 }
5942
Amith Yamasani04e0d262012-02-14 11:50:53 -08005943 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5944 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005945 // Fast path - check if account is already cached
5946 synchronized (accounts.cacheLock) {
5947 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5948 if (authTokensForAccount != null) {
5949 return authTokensForAccount.get(authTokenType);
5950 }
5951 }
5952 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005953 synchronized (accounts.dbLock) {
5954 synchronized (accounts.cacheLock) {
5955 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5956 if (authTokensForAccount == null) {
5957 // need to populate the cache for this account
5958 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
5959 accounts.authTokenCache.put(account, authTokensForAccount);
5960 }
5961 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08005962 }
Fred Quintana56285a62010-12-02 14:20:51 -08005963 }
5964 }
5965
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005966 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
5967 Map<String, String> userDataForAccount;
5968 // Fast path - check if data is already cached
5969 synchronized (accounts.cacheLock) {
5970 userDataForAccount = accounts.userDataCache.get(account);
5971 }
5972 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00005973 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005974 synchronized (accounts.dbLock) {
5975 synchronized (accounts.cacheLock) {
5976 userDataForAccount = accounts.userDataCache.get(account);
5977 if (userDataForAccount == null) {
5978 // need to populate the cache for this account
5979 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
5980 accounts.userDataCache.put(account, userDataForAccount);
5981 }
5982 }
5983 }
Fred Quintana56285a62010-12-02 14:20:51 -08005984 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005985 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005986 }
5987
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005988 private Context getContextForUser(UserHandle user) {
5989 try {
5990 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5991 } catch (NameNotFoundException e) {
5992 // Default to mContext, not finding the package system is running as is unlikely.
5993 return mContext;
5994 }
5995 }
Sandra Kwan78812282015-11-04 11:19:47 -08005996
5997 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5998 try {
5999 response.onResult(result);
6000 } catch (RemoteException e) {
6001 // if the caller is dead then there is no one to care about remote
6002 // exceptions
6003 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6004 Log.v(TAG, "failure while notifying response", e);
6005 }
6006 }
6007 }
6008
6009 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6010 String errorMessage) {
6011 try {
6012 response.onError(errorCode, errorMessage);
6013 } catch (RemoteException e) {
6014 // if the caller is dead then there is no one to care about remote
6015 // exceptions
6016 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6017 Log.v(TAG, "failure while notifying response", e);
6018 }
6019 }
6020 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006021
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006022 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07006023 private final Object mLock = new Object();
6024
6025 @GuardedBy("mLock")
6026 private AccountManagerBackupHelper mBackupHelper;
6027
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006028 @Override
6029 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6030 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6031 if (account == null) {
6032 Slog.w(TAG, "account cannot be null");
6033 return;
6034 }
6035 if (packageName == null) {
6036 Slog.w(TAG, "packageName cannot be null");
6037 return;
6038 }
6039 if (userId < UserHandle.USER_SYSTEM) {
6040 Slog.w(TAG, "user id must be concrete");
6041 return;
6042 }
6043 if (callback == null) {
6044 Slog.w(TAG, "callback cannot be null");
6045 return;
6046 }
6047
Dmitry Dementyev7b3ea132017-05-10 12:45:02 -07006048 int visibility =
6049 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6050 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6051 Slog.w(TAG, "requestAccountAccess: account is hidden");
6052 return;
6053 }
6054
Svet Ganovf6d424f12016-09-20 20:18:53 -07006055 if (AccountManagerService.this.hasAccountAccess(account, packageName,
6056 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006057 Bundle result = new Bundle();
6058 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6059 callback.sendResult(result);
6060 return;
6061 }
6062
6063 final int uid;
6064 try {
6065 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6066 } catch (NameNotFoundException e) {
6067 Slog.e(TAG, "Unknown package " + packageName);
6068 return;
6069 }
6070
6071 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006072 final UserAccounts userAccounts;
6073 synchronized (mUsers) {
6074 userAccounts = mUsers.get(userId);
6075 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04006076 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006077 doNotification(userAccounts, account, null, intent, packageName, userId);
6078 }
6079
6080 @Override
6081 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6082 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6083 mAppPermissionChangeListeners.add(listener);
6084 }
6085
6086 @Override
6087 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6088 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006089 }
Svet Ganov5d09c992016-09-07 09:57:41 -07006090
6091 @Override
6092 public byte[] backupAccountAccessPermissions(int userId) {
6093 synchronized (mLock) {
6094 if (mBackupHelper == null) {
6095 mBackupHelper = new AccountManagerBackupHelper(
6096 AccountManagerService.this, this);
6097 }
6098 return mBackupHelper.backupAccountAccessPermissions(userId);
6099 }
6100 }
6101
6102 @Override
6103 public void restoreAccountAccessPermissions(byte[] data, int userId) {
6104 synchronized (mLock) {
6105 if (mBackupHelper == null) {
6106 mBackupHelper = new AccountManagerBackupHelper(
6107 AccountManagerService.this, this);
6108 }
6109 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6110 }
6111 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006112 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07006113
6114 @VisibleForTesting
6115 static class Injector {
6116 private final Context mContext;
6117
6118 public Injector(Context context) {
6119 mContext = context;
6120 }
6121
6122 Looper getMessageHandlerLooper() {
6123 ServiceThread serviceThread = new ServiceThread(TAG,
6124 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6125 serviceThread.start();
6126 return serviceThread.getLooper();
6127 }
6128
6129 Context getContext() {
6130 return mContext;
6131 }
6132
6133 void addLocalService(AccountManagerInternal service) {
6134 LocalServices.addService(AccountManagerInternal.class, service);
6135 }
6136
6137 String getDeDatabaseName(int userId) {
6138 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6139 AccountsDb.DE_DATABASE_NAME);
6140 return databaseFile.getPath();
6141 }
6142
6143 String getCeDatabaseName(int userId) {
6144 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6145 AccountsDb.CE_DATABASE_NAME);
6146 return databaseFile.getPath();
6147 }
6148
6149 String getPreNDatabaseName(int userId) {
6150 File systemDir = Environment.getDataSystemDirectory();
6151 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6152 PRE_N_DATABASE_NAME);
6153 if (userId == 0) {
6154 // Migrate old file, if it exists, to the new location.
6155 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006156 // accidentally created in the old location,
6157 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07006158 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6159 if (oldFile.exists() && !databaseFile.exists()) {
6160 // Check for use directory; create if it doesn't exist, else renameTo will fail
6161 File userDir = Environment.getUserSystemDirectory(userId);
6162 if (!userDir.exists()) {
6163 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006164 throw new IllegalStateException(
6165 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006166 }
6167 }
6168 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006169 throw new IllegalStateException(
6170 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006171 }
6172 }
6173 }
6174 return databaseFile.getPath();
6175 }
6176
6177 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6178 return new AccountAuthenticatorCache(mContext);
6179 }
6180
6181 INotificationManager getNotificationManager() {
6182 return NotificationManager.getService();
6183 }
6184 }
Chris Wren717a8812017-03-31 15:34:39 -04006185
Andrew Scullc7770d62017-05-22 17:49:58 +01006186 private static class NotificationId {
Chris Wren717a8812017-03-31 15:34:39 -04006187 final String mTag;
6188 private final int mId;
6189
6190 NotificationId(String tag, int type) {
6191 mTag = tag;
6192 mId = type;
6193 }
6194 }
Fred Quintana60307342009-03-24 22:48:12 -07006195}