blob: eb58e4c5424618b1eae968cf1f2779cda624b1e0 [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;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080026import android.accounts.AuthenticatorDescription;
Amith Yamasani23c8b962013-04-10 13:37:18 -070027import android.accounts.CantAddAccountActivity;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080028import android.accounts.GrantCredentialsPermissionActivity;
29import android.accounts.IAccountAuthenticator;
30import android.accounts.IAccountAuthenticatorResponse;
31import android.accounts.IAccountManager;
32import android.accounts.IAccountManagerResponse;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070033import android.annotation.IntRange;
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070034import android.annotation.NonNull;
Svet Ganovf6d424f12016-09-20 20:18:53 -070035import android.annotation.Nullable;
Brett Chabot3b4fcbc2011-01-09 13:41:02 -080036import android.app.ActivityManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070037import android.app.ActivityThread;
Svetoslavf3f02ac2015-09-08 14:36:35 -070038import android.app.AppOpsManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070039import android.app.INotificationManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070040import android.app.Notification;
41import android.app.NotificationManager;
42import android.app.PendingIntent;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000043import android.app.admin.DeviceAdminInfo;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010044import android.app.admin.DevicePolicyManager;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000045import android.app.admin.DevicePolicyManagerInternal;
Fred Quintanaa698f422009-04-08 19:14:54 -070046import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070047import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070048import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070051import android.content.IntentSender;
Fred Quintanab839afc2009-10-14 15:57:28 -070052import android.content.ServiceConnection;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -080053import android.content.pm.ActivityInfo;
Doug Zongker885cfc232009-10-21 16:52:44 -070054import android.content.pm.ApplicationInfo;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070055import android.content.pm.IPackageManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070056import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070057import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070058import android.content.pm.PackageManager.NameNotFoundException;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070059import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070060import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070061import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070062import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070063import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070064import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070065import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070066import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070067import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080068import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070069import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070070import android.os.IBinder;
71import android.os.Looper;
72import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070073import android.os.Parcel;
Amith Yamasani27db4682013-03-30 17:07:47 -070074import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070075import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070076import android.os.RemoteException;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080077import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070078import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070079import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070080import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070081import android.text.TextUtils;
82import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070083import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070084import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080085import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070086import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070087
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070088import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070089import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070090import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070091import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040092import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050093import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080094import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060095import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080096import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -070097import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000098import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -070099import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600100import com.android.server.SystemService;
101
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700102import com.google.android.collect.Lists;
103import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700104
Oscar Montemayora8529f62009-11-18 10:14:20 -0800105import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700106import java.io.FileDescriptor;
107import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800108import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700109import java.security.MessageDigest;
110import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700111import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700112import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800113import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700114import java.util.Collection;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700115import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700116import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700117import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800118import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700119import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800120import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800121import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700122import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700123import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700124import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700125import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700126import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700127
Fred Quintana60307342009-03-24 22:48:12 -0700128/**
129 * A system service that provides account, password, and authtoken management for all
130 * accounts on the device. Some of these calls are implemented with the help of the corresponding
131 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
132 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700133 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700134 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700135 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700136public class AccountManagerService
137 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800138 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700139 private static final String TAG = "AccountManagerService";
140
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600141 public static class Lifecycle extends SystemService {
142 private AccountManagerService mService;
143
144 public Lifecycle(Context context) {
145 super(context);
146 }
147
148 @Override
149 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700150 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600151 publishBinderService(Context.ACCOUNT_SERVICE, mService);
152 }
153
154 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600155 public void onUnlockUser(int userHandle) {
156 mService.onUnlockUser(userHandle);
157 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700158
159 @Override
160 public void onCleanupUser(int userHandle) {
161 mService.onCleanupUser(userHandle);
162 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600163 }
164
Svet Ganov5d09c992016-09-07 09:57:41 -0700165 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700166
Fred Quintana56285a62010-12-02 14:20:51 -0800167 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700168 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700169 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700170 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800171
Svet Ganov5d09c992016-09-07 09:57:41 -0700172 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700173
Fred Quintana60307342009-03-24 22:48:12 -0700174 // Messages that can be sent on mHandler
175 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700176 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700177
Fred Quintana56285a62010-12-02 14:20:51 -0800178 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700179 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700180 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800181
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800182 private static final int SIGNATURE_CHECK_MISMATCH = 0;
183 private static final int SIGNATURE_CHECK_MATCH = 1;
184 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
185
Carlos Valdivia91979be2015-05-22 14:11:35 -0700186 static {
187 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800188 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
189 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700190 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700191
192 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700193
Amith Yamasani04e0d262012-02-14 11:50:53 -0800194 static class UserAccounts {
195 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700196 final AccountsDb accountsDb;
Chris Wren717a8812017-03-31 15:34:39 -0400197 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
198 credentialsPermissionNotificationIds = new HashMap<>();
199 private final HashMap<Account, NotificationId> signinRequiredNotificationIds
200 = new HashMap<>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700201 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700202 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800203 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700204 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800205 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700206 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800207 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700208 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700209 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700210 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700211 /** protected by the {@link #cacheLock} */
212 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700213
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700214 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700215 * type -> (packageName -> number of active receivers)
216 * type == null is used to get notifications about all account types
217 */
218 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800219
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700220 /**
221 * protected by the {@link #cacheLock}
222 *
223 * Caches the previous names associated with an account. Previous names
224 * should be cached because we expect that when an Account is renamed,
225 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
226 * want to know if the accounts they care about have been renamed.
227 *
228 * The previous names are wrapped in an {@link AtomicReference} so that
229 * we can distinguish between those accounts with no previous names and
230 * those whose previous names haven't been cached (yet).
231 */
232 private final HashMap<Account, AtomicReference<String>> previousNameCache =
233 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800234
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700235 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700236 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700237
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700238 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800239 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700240 synchronized (dbLock) {
241 synchronized (cacheLock) {
242 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
243 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800244 }
245 }
246 }
247
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700248 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600249 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700250 // Not thread-safe. Only use in synchronized context
251 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700252 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
253 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800254
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700255 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700256 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700257
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700258 /**
259 * This should only be called by system code. One should only call this after the service
260 * has started.
261 * @return a reference to the AccountManagerService instance
262 * @hide
263 */
264 public static AccountManagerService getSingleton() {
265 return sThis.get();
266 }
Fred Quintana60307342009-03-24 22:48:12 -0700267
Fyodor Kupolovda993802016-09-21 14:47:10 -0700268 public AccountManagerService(Injector injector) {
269 mInjector = injector;
270 mContext = injector.getContext();
271 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700272 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700273 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
274 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800275 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700276
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700277 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800278
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800279 IntentFilter intentFilter = new IntentFilter();
280 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
281 intentFilter.addDataScheme("package");
282 mContext.registerReceiver(new BroadcastReceiver() {
283 @Override
284 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700285 // Don't delete accounts when updating a authenticator's
286 // package.
287 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700288 /* Purging data requires file io, don't block the main thread. This is probably
289 * less than ideal because we are introducing a race condition where old grants
290 * could be exercised until they are purged. But that race condition existed
291 * anyway with the broadcast receiver.
292 *
293 * Ideally, we would completely clear the cache, purge data from the database,
294 * and then rebuild the cache. All under the cache lock. But that change is too
295 * large at this point.
296 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800297 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700298 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700299 @Override
300 public void run() {
301 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800302 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800303 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700304 }
305 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700306 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700307 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800308 }
309 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800310
Fyodor Kupolovda993802016-09-21 14:47:10 -0700311 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700312
313 // Need to cancel account request notifications if the update/install can access the account
314 new PackageMonitor() {
315 @Override
316 public void onPackageAdded(String packageName, int uid) {
317 // Called on a handler, and running as the system
318 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
319 }
320
321 @Override
322 public void onPackageUpdateFinished(String packageName, int uid) {
323 // Called on a handler, and running as the system
324 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
325 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700326 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700327
328 // Cancel account request notification if an app op was preventing the account access
329 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
330 new AppOpsManager.OnOpChangedInternalListener() {
331 @Override
332 public void onOpChanged(int op, String packageName) {
333 try {
334 final int userId = ActivityManager.getCurrentUser();
335 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
336 final int mode = mAppOpsManager.checkOpNoThrow(
337 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
338 if (mode == AppOpsManager.MODE_ALLOWED) {
339 final long identity = Binder.clearCallingIdentity();
340 try {
341 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
342 } finally {
343 Binder.restoreCallingIdentity(identity);
344 }
345 }
346 } catch (NameNotFoundException e) {
347 /* ignore */
348 }
349 }
350 });
351
352 // Cancel account request notification if a permission was preventing the account access
353 mPackageManager.addOnPermissionsChangeListener(
354 (int uid) -> {
355 Account[] accounts = null;
356 String[] packageNames = mPackageManager.getPackagesForUid(uid);
357 if (packageNames != null) {
358 final int userId = UserHandle.getUserId(uid);
359 final long identity = Binder.clearCallingIdentity();
360 try {
361 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800362 // if app asked for permission we need to cancel notification even
363 // for O+ applications.
364 if (mPackageManager.checkPermission(
365 Manifest.permission.GET_ACCOUNTS,
366 packageName) != PackageManager.PERMISSION_GRANTED) {
367 continue;
368 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700369
370 if (accounts == null) {
371 accounts = getAccountsAsUser(null, userId, "android");
372 if (ArrayUtils.isEmpty(accounts)) {
373 return;
374 }
375 }
376
377 for (Account account : accounts) {
378 cancelAccountAccessRequestNotificationIfNeeded(
379 account, uid, packageName, true);
380 }
381 }
382 } finally {
383 Binder.restoreCallingIdentity(identity);
384 }
385 }
386 });
387 }
388
389 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
390 boolean checkAccess) {
391 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
392 for (Account account : accounts) {
393 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
394 }
395 }
396
397 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
398 boolean checkAccess) {
399 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
400 for (Account account : accounts) {
401 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
402 }
403 }
404
405 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
406 boolean checkAccess) {
407 String[] packageNames = mPackageManager.getPackagesForUid(uid);
408 if (packageNames != null) {
409 for (String packageName : packageNames) {
410 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
411 packageName, checkAccess);
412 }
413 }
414 }
415
416 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
417 int uid, String packageName, boolean checkAccess) {
418 if (!checkAccess || hasAccountAccess(account, packageName,
419 UserHandle.getUserHandleForUid(uid))) {
420 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700421 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700422 UserHandle.getUserHandleForUid(uid));
423 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800424 }
425
Dianne Hackborn164371f2013-10-01 19:10:13 -0700426 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800427 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800428 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800429 Bundle.setDefusable(extras, true);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700430 int callingUid = Binder.getCallingUid();
431 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800432 if (Log.isLoggable(TAG, Log.VERBOSE)) {
433 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
434 + ", pid " + Binder.getCallingPid());
435 }
436 Preconditions.checkNotNull(account, "account cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800437 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
438 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
439 callingUid, account.type);
440 throw new SecurityException(msg);
441 }
442 /*
443 * Child users are not allowed to add accounts. Only the accounts that are shared by the
444 * parent profile can be added to child profile.
445 *
446 * TODO: Only allow accounts that were shared to be added by a limited user.
447 */
448 // fails if the account already exists
449 long identityToken = clearCallingIdentity();
450 try {
451 UserAccounts accounts = getUserAccounts(userId);
452 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800453 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800454 } finally {
455 restoreCallingIdentity(identityToken);
456 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700457 }
458
459 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800460 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
461 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800462 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700463 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800464 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700465 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800466
467 if ((accountType != null && !managedTypes.contains(accountType))
468 || (accountType == null && !isSystemUid)) {
469 throw new SecurityException(
470 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
471 + callingUid + " with packageName=" + packageName);
472 }
473 if (accountType != null) {
474 managedTypes = new ArrayList<String>();
475 managedTypes.add(accountType);
476 }
477
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800478 long identityToken = clearCallingIdentity();
479 try {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700480 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800481 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700482 accounts);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800483 } finally {
484 restoreCallingIdentity(identityToken);
485 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800486 }
487
488 /*
489 * accountTypes may not be null
490 */
491 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
492 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700493 if (!packageExistsForUser(packageName, accounts.userId)) {
494 Log.d(TAG, "Package not found " + packageName);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800495 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800496 }
497
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800498 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800499 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700500 synchronized (accounts.dbLock) {
501 synchronized (accounts.cacheLock) {
502 final Account[] accountsOfType = accounts.accountCache.get(accountType);
503 if (accountsOfType != null) {
504 for (Account account : accountsOfType) {
505 result.put(account,
506 resolveAccountVisibility(account, packageName, accounts));
507 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800508 }
509 }
510 }
511 }
512 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800513 }
514
515 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800516 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700517 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700518 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700519 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800520 if (!isAccountManagedByCaller(account.type, callingUid, userId)
521 && !isSystemUid(callingUid)) {
522 String msg =
523 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700524 throw new SecurityException(msg);
525 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700526
527 long identityToken = clearCallingIdentity();
528 try {
529 UserAccounts accounts = getUserAccounts(userId);
530 synchronized (accounts.dbLock) {
531 synchronized (accounts.cacheLock) {
532 return getPackagesAndVisibilityForAccountLocked(account, accounts);
533 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700534 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700535 } finally {
536 restoreCallingIdentity(identityToken);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700537 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700538
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800539 }
540
541 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700542 * Returns Map with all package names and visibility values for given account.
543 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800544 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800545 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800546 * @param accounts UserAccount that currently hosts the account and application
547 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700548 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800549 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700550 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800551 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700552 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
553 if (accountVisibility == null) {
554 Log.d(TAG, "Visibility was not initialized");
555 accountVisibility = new HashMap<>();
556 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800557 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700558 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700559 }
560
561 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700562 public int getAccountVisibility(Account account, String packageName) {
563 Preconditions.checkNotNull(account, "account cannot be null");
564 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800565 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700566 int userId = UserHandle.getCallingUserId();
567 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800568 && !isSystemUid(callingUid)) {
569 String msg = String.format(
570 "uid %s cannot get secrets for accounts of type: %s",
571 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700572 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800573 throw new SecurityException(msg);
574 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700575 long identityToken = clearCallingIdentity();
576 try {
577 UserAccounts accounts = getUserAccounts(userId);
578 return resolveAccountVisibility(account, packageName, accounts);
579 } finally {
580 restoreCallingIdentity(identityToken);
581 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800582 }
583
584 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800585 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800586 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800587 * @param account The account to check visibility.
588 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800589 * @param accounts UserAccount that currently hosts the account and application
590 *
591 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
592 *
593 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700594 private int getAccountVisibilityFromCache(Account account, String packageName,
595 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700596 synchronized (accounts.cacheLock) {
597 Map<String, Integer> accountVisibility =
598 getPackagesAndVisibilityForAccountLocked(account, accounts);
599 Integer visibility = accountVisibility.get(packageName);
600 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800601 }
602 }
603
604 /**
605 * Method which handles default values for Account visibility.
606 *
607 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800608 * @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, the method never returns AccountManager.VISIBILITY_UNDEFINED
612 *
613 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800614 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800615 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800616 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800617 int uid = -1;
618 try {
619 long identityToken = clearCallingIdentity();
620 try {
621 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
622 } finally {
623 restoreCallingIdentity(identityToken);
624 }
625 } catch (NameNotFoundException e) {
626 Log.d(TAG, "Package not found " + e.getMessage());
627 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800628 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800629
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800630 // System visibility can not be restricted.
631 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
632 return AccountManager.VISIBILITY_VISIBLE;
633 }
634
635 int signatureCheckResult =
636 checkPackageSignature(account.type, uid, accounts.userId);
637
638 // Authenticator can not restrict visibility to itself.
639 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
640 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
641 }
642
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800643 if (isSpecialPackageKey(packageName)) {
644 Log.d(TAG, "Package name is forbidden: " + packageName);
645 return AccountManager.VISIBILITY_NOT_VISIBLE;
646 }
647
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800648 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700649 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800650
651 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
652 return visibility;
653 }
654
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700655 boolean isPrivileged = isPermittedForPackage(packageName, uid, accounts.userId,
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800656 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
657
658 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800659 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800660 return AccountManager.VISIBILITY_VISIBLE;
661 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800662
663 boolean preO = isPreOApplication(packageName);
664 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700665 || (preO && checkGetAccountsPermission(packageName, uid, accounts.userId))
666 || (checkReadContactsPermission(packageName, uid, accounts.userId)
667 && accountTypeManagesContacts(account.type, accounts.userId))
668 || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800669 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
670 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700671 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800672 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800673 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
674 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
675 }
676 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700677 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800678 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800679 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
680 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
681 }
682 }
683 return visibility;
684 }
685
686 /**
687 * Checks targetSdk for a package;
688 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800689 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800690 *
691 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
692 * undefined
693 */
694 private boolean isPreOApplication(String packageName) {
695 try {
696 long identityToken = clearCallingIdentity();
697 ApplicationInfo applicationInfo;
698 try {
699 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
700 } finally {
701 restoreCallingIdentity(identityToken);
702 }
703
704 if (applicationInfo != null) {
705 int version = applicationInfo.targetSdkVersion;
706 return version < android.os.Build.VERSION_CODES.O;
707 }
708 return true;
709 } catch (NameNotFoundException e) {
710 Log.d(TAG, "Package not found " + e.getMessage());
711 return true;
712 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800713 }
714
715 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700716 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
717 Preconditions.checkNotNull(account, "account cannot be null");
718 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800719 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700720 int userId = UserHandle.getCallingUserId();
721 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800722 && !isSystemUid(callingUid)) {
723 String msg = String.format(
724 "uid %s cannot get secrets for accounts of type: %s",
725 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700726 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800727 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700728 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700729 long identityToken = clearCallingIdentity();
730 try {
731 UserAccounts accounts = getUserAccounts(userId);
732 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700733 accounts);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700734 } finally {
735 restoreCallingIdentity(identityToken);
736 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700737 }
738
739 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800740 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700741 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800742 * @param account Account to update visibility.
743 * @param packageName Package name for which visibility is updated.
744 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800745 * @param notify if the flag is set applications will get notification about visibility change
746 * @param accounts UserAccount that currently hosts the account and application
747 *
748 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700749 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800750 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800751 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700752 synchronized (accounts.dbLock) {
753 synchronized (accounts.cacheLock) {
754 Map<String, Integer> packagesToVisibility;
755 if (notify) {
756 if (isSpecialPackageKey(packageName)) {
757 packagesToVisibility =
758 getRequestingPackages(account, accounts);
759 } else {
760 if (!packageExistsForUser(packageName, accounts.userId)) {
761 return false; // package is not installed.
762 }
763 packagesToVisibility = new HashMap<>();
764 packagesToVisibility.put(packageName,
765 resolveAccountVisibility(account, packageName, accounts));
766 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800767 } else {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700768 // Notifications will not be send.
769 if (!isSpecialPackageKey(packageName) &&
770 !packageExistsForUser(packageName, accounts.userId)) {
771 // package is not installed and not meta value.
772 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100773 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700774 packagesToVisibility = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800775 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700776
777 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800778 return false;
779 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800780
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700781 if (notify) {
782 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
783 .entrySet()) {
784 if (packageToVisibility.getValue()
785 != AccountManager.VISIBILITY_NOT_VISIBLE) {
786 notifyPackage(packageToVisibility.getKey(), accounts);
787 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700788 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700789 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700790 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700791 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800792 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700793 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700794 }
795
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700796 // Update account visibility in cache and database.
797 private boolean updateAccountVisibilityLocked(Account account, String packageName,
798 int newVisibility, UserAccounts accounts) {
799 final long accountId = accounts.accountsDb.findDeAccountId(account);
800 if (accountId < 0) {
801 return false;
802 }
803
804 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
805 try {
806 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
807 newVisibility)) {
808 return false;
809 }
810 } finally {
811 StrictMode.setThreadPolicy(oldPolicy);
812 }
813 Map<String, Integer> accountVisibility =
814 getPackagesAndVisibilityForAccountLocked(account, accounts);
815 accountVisibility.put(packageName, newVisibility);
816 return true;
817 }
818
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700819 @Override
820 public void registerAccountListener(String[] accountTypes, String opPackageName) {
821 int callingUid = Binder.getCallingUid();
822 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700823
824 int userId = UserHandle.getCallingUserId();
825 long identityToken = clearCallingIdentity();
826 try {
827 UserAccounts accounts = getUserAccounts(userId);
828 registerAccountListener(accountTypes, opPackageName, accounts);
829 } finally {
830 restoreCallingIdentity(identityToken);
831 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800832 }
833
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700834 private void registerAccountListener(String[] accountTypes, String opPackageName,
835 UserAccounts accounts) {
836 synchronized (accounts.mReceiversForType) {
837 if (accountTypes == null) {
838 // null for any type
839 accountTypes = new String[] {null};
840 }
841 for (String type : accountTypes) {
842 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
843 if (receivers == null) {
844 receivers = new HashMap<>();
845 accounts.mReceiversForType.put(type, receivers);
846 }
847 Integer cnt = receivers.get(opPackageName);
848 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800849 }
850 }
851 }
852
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700853 @Override
854 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
855 int callingUid = Binder.getCallingUid();
856 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700857 int userId = UserHandle.getCallingUserId();
858 long identityToken = clearCallingIdentity();
859 try {
860 UserAccounts accounts = getUserAccounts(userId);
861 unregisterAccountListener(accountTypes, opPackageName, accounts);
862 } finally {
863 restoreCallingIdentity(identityToken);
864 }
865 }
866
867 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
868 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700869 synchronized (accounts.mReceiversForType) {
870 if (accountTypes == null) {
871 // null for any type
872 accountTypes = new String[] {null};
873 }
874 for (String type : accountTypes) {
875 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
876 if (receivers == null || receivers.get(opPackageName) == null) {
877 throw new IllegalArgumentException("attempt to unregister wrong receiver");
878 }
879 Integer cnt = receivers.get(opPackageName);
880 if (cnt == 1) {
881 receivers.remove(opPackageName);
882 } else {
883 receivers.put(opPackageName, cnt - 1);
884 }
885 }
886 }
887 }
888
889 // Send notification to all packages which can potentially see the account
890 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
891 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
892 // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
893 // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
894 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
895 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
896 notifyPackage(packageToVisibility.getKey(), accounts);
897 }
898 }
899 }
900
901 /**
902 * Sends a direct intent to a package, notifying it of account visibility change.
903 *
904 * @param packageName to send Account to
905 * @param accounts UserAccount that currently hosts the account
906 */
907 private void notifyPackage(String packageName, UserAccounts accounts) {
908 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
909 intent.setPackage(packageName);
910 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
911 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
912 }
913
914 // Returns a map from package name to visibility, for packages subscribed
915 // to notifications about any account type, or type of provided account
916 // account type or all types.
917 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
918 Set<String> packages = new HashSet<>();
919 synchronized (accounts.mReceiversForType) {
920 for (String type : new String[] {account.type, null}) {
921 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
922 if (receivers != null) {
923 packages.addAll(receivers.keySet());
924 }
925 }
926 }
927 Map<String, Integer> result = new HashMap<>();
928 for (String packageName : packages) {
929 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
930 }
931 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800932 }
933
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800934 private boolean packageExistsForUser(String packageName, int userId) {
935 try {
936 long identityToken = clearCallingIdentity();
937 try {
938 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700939 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800940 } finally {
941 restoreCallingIdentity(identityToken);
942 }
943 } catch (NameNotFoundException e) {
944 return false;
945 }
946 }
947
948 /**
949 * Returns true if packageName is one of special values.
950 */
951 private boolean isSpecialPackageKey(String packageName) {
952 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
953 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
954 }
955
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800956 private void sendAccountsChangedBroadcast(int userId) {
957 Log.i(TAG, "the accounts changed, sending broadcast of "
958 + ACCOUNTS_CHANGED_INTENT.getAction());
959 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700960 }
961
Dmitry Dementyeva461e302017-04-12 11:00:48 -0700962 private void sendAccountRemovedBroadcast(int userId) {
963 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
964 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
965 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
966 }
967
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700968 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700969 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
970 throws RemoteException {
971 try {
972 return super.onTransact(code, data, reply, flags);
973 } catch (RuntimeException e) {
974 // The account manager only throws security exceptions, so let's
975 // log all others.
976 if (!(e instanceof SecurityException)) {
977 Slog.wtf(TAG, "Account Manager Crash", e);
978 }
979 throw e;
980 }
981 }
982
Amith Yamasani258848d2012-08-10 17:06:33 -0700983 private UserManager getUserManager() {
984 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700985 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700986 }
987 return mUserManager;
988 }
989
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700990 /**
991 * Validate internal set of accounts against installed authenticators for
992 * given user. Clears cached authenticators before validating.
993 */
994 public void validateAccounts(int userId) {
995 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700996 // Invalidate user-specific cache to make sure we catch any
997 // removed authenticators.
998 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
999 }
1000
1001 /**
1002 * Validate internal set of accounts against installed authenticators for
1003 * given user. Clear cached authenticators before validating when requested.
1004 */
1005 private void validateAccountsInternal(
1006 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001007 if (Log.isLoggable(TAG, Log.DEBUG)) {
1008 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001009 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001010 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001011 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001012
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001013 if (invalidateAuthenticatorCache) {
1014 mAuthenticatorCache.invalidateCache(accounts.userId);
1015 }
1016
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001017 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1018 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001019 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001020
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001021 synchronized (accounts.dbLock) {
1022 synchronized (accounts.cacheLock) {
1023 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001024
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001025 // Get a map of stored authenticator types to UID
1026 final AccountsDb accountsDb = accounts.accountsDb;
1027 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1028 // Create a list of authenticator type whose previous uid no longer exists
1029 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1030 SparseBooleanArray knownUids = null;
1031 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1032 String type = authToUidEntry.getKey();
1033 int uid = authToUidEntry.getValue();
1034 Integer knownUid = knownAuth.get(type);
1035 if (knownUid != null && uid == knownUid) {
1036 // Remove it from the knownAuth list if it's unchanged.
1037 knownAuth.remove(type);
1038 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001039 /*
1040 * The authenticator is presently not cached and should only be triggered
1041 * when we think an authenticator has been removed (or is being updated).
1042 * But we still want to check if any data with the associated uid is
1043 * around. This is an (imperfect) signal that the package may be updating.
1044 *
1045 * A side effect of this is that an authenticator sharing a uid with
1046 * multiple apps won't get its credentials wiped as long as some app with
1047 * that uid is still on the device. But I suspect that this is a rare case.
1048 * And it isn't clear to me how an attacker could really exploit that
1049 * feature.
1050 *
1051 * The upshot is that we don't have to worry about accounts getting
1052 * uninstalled while the authenticator's package is being updated.
1053 *
1054 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001055 if (knownUids == null) {
1056 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1057 }
1058 if (!knownUids.get(uid)) {
1059 // The authenticator is not presently available to the cache. And the
1060 // package no longer has a data directory (so we surmise it isn't
1061 // updating). So purge its data from the account databases.
1062 obsoleteAuthType.add(type);
1063 // And delete it from the TABLE_META
1064 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1065 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001066 }
1067 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001068
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001069 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1070 // been re-enabled (after being updated for example), then we just overwrite the old
1071 // values.
1072 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1073 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1074 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001075
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001076 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1077 try {
1078 accounts.accountCache.clear();
1079 final HashMap<String, ArrayList<String>> accountNamesByType
1080 = new LinkedHashMap<>();
1081 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1082 final long accountId = accountEntry.getKey();
1083 final Account account = accountEntry.getValue();
1084 if (obsoleteAuthType.contains(account.type)) {
1085 Slog.w(TAG, "deleting account " + account.name + " because type "
1086 + account.type
1087 + "'s registered authenticator no longer exist.");
1088 Map<String, Integer> packagesToVisibility =
1089 getRequestingPackages(account, accounts);
1090 accountsDb.beginTransaction();
1091 try {
1092 accountsDb.deleteDeAccount(accountId);
1093 // Also delete from CE table if user is unlocked; if user is
1094 // currently locked the account will be removed later by
1095 // syncDeCeAccountsLocked
1096 if (userUnlocked) {
1097 accountsDb.deleteCeAccount(accountId);
1098 }
1099 accountsDb.setTransactionSuccessful();
1100 } finally {
1101 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001102 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001103 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001104
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001105 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1106 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001107
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001108 accounts.userDataCache.remove(account);
1109 accounts.authTokenCache.remove(account);
1110 accounts.accountTokenCaches.remove(account);
1111 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001112
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001113 for (Entry<String, Integer> packageToVisibility :
1114 packagesToVisibility.entrySet()) {
1115 if (packageToVisibility.getValue()
1116 != AccountManager.VISIBILITY_NOT_VISIBLE) {
1117 notifyPackage(packageToVisibility.getKey(), accounts);
1118 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001119 }
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001120 sendAccountRemovedBroadcast(accounts.userId);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001121 } else {
1122 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1123 if (accountNames == null) {
1124 accountNames = new ArrayList<>();
1125 accountNamesByType.put(account.type, accountNames);
1126 }
1127 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001128 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001129 }
1130 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1131 final String accountType = cur.getKey();
1132 final ArrayList<String> accountNames = cur.getValue();
1133 final Account[] accountsForType = new Account[accountNames.size()];
1134 for (int i = 0; i < accountsForType.length; i++) {
1135 accountsForType[i] = new Account(accountNames.get(i), accountType,
1136 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001137 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001138 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001139 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001140 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1141 } finally {
1142 if (accountDeleted) {
1143 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001144 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001145 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001146 }
1147 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001148 }
1149
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001150 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1151 // Get the UIDs of all apps that might have data on the device. We want
1152 // to preserve user data if the app might otherwise be storing data.
1153 List<PackageInfo> pkgsWithData =
1154 mPackageManager.getInstalledPackagesAsUser(
1155 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1156 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1157 for (PackageInfo pkgInfo : pkgsWithData) {
1158 if (pkgInfo.applicationInfo != null
1159 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1160 knownUids.put(pkgInfo.applicationInfo.uid, true);
1161 }
1162 }
1163 return knownUids;
1164 }
1165
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001166 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001167 Context context,
1168 int userId) {
1169 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001170 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1171 }
1172
1173 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1174 IAccountAuthenticatorCache authCache,
1175 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001176 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001177 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1178 .getAllServices(userId)) {
1179 knownAuth.put(service.type.type, service.uid);
1180 }
1181 return knownAuth;
1182 }
1183
Amith Yamasani04e0d262012-02-14 11:50:53 -08001184 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001185 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001186 }
1187
1188 protected UserAccounts getUserAccounts(int userId) {
1189 synchronized (mUsers) {
1190 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001191 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001192 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001193 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1194 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001195 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001196 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001197 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001198 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001199 validateAccounts = true;
1200 }
1201 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001202 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001203 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001204 synchronized (accounts.dbLock) {
1205 synchronized (accounts.cacheLock) {
1206 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1207 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1208 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001209 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001210 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001211 }
1212 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001213 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001214 }
1215 return accounts;
1216 }
1217 }
1218
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001219 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1220 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001221 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001222 if (!accountsToRemove.isEmpty()) {
1223 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1224 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001225 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1226 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001227
1228 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001229 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001230 }
1231 }
1232 }
1233
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001234 private void purgeOldGrantsAll() {
1235 synchronized (mUsers) {
1236 for (int i = 0; i < mUsers.size(); i++) {
1237 purgeOldGrants(mUsers.valueAt(i));
1238 }
1239 }
1240 }
1241
1242 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001243 synchronized (accounts.dbLock) {
1244 synchronized (accounts.cacheLock) {
1245 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1246 for (int uid : uids) {
1247 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1248 if (packageExists) {
1249 continue;
1250 }
1251 Log.d(TAG, "deleting grants for UID " + uid
1252 + " because its package is no longer installed");
1253 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001254 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001255 }
1256 }
1257 }
1258
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001259 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001260 if (isSpecialPackageKey(packageName)) {
1261 return;
1262 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001263 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001264 int numberOfUsers = mUsers.size();
1265 for (int i = 0; i < numberOfUsers; i++) {
1266 UserAccounts accounts = mUsers.valueAt(i);
1267 try {
1268 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1269 } catch (NameNotFoundException e) {
1270 // package does not exist - remove visibility values
1271 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001272 synchronized (accounts.dbLock) {
1273 synchronized (accounts.cacheLock) {
1274 for (Account account : accounts.visibilityCache.keySet()) {
1275 Map<String, Integer> accountVisibility =
1276 getPackagesAndVisibilityForAccountLocked(account, accounts);
1277 accountVisibility.remove(packageName);
1278 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001279 }
1280 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001281 }
1282 }
1283 }
1284 }
1285
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001286
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -07001287 private void onCleanupUser(int userId) {
1288 Log.i(TAG, "onCleanupUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001289 UserAccounts accounts;
1290 synchronized (mUsers) {
1291 accounts = mUsers.get(userId);
1292 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001293 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001294 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001295 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001296 synchronized (accounts.dbLock) {
1297 synchronized (accounts.cacheLock) {
1298 accounts.accountsDb.close();
1299 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001300 }
Amith Yamasani13593602012-03-22 16:16:17 -07001301 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001302 }
1303
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001304 @VisibleForTesting
1305 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001306 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1307 }
1308
1309 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001310 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1311 Log.v(TAG, "onUserUnlocked " + userId);
1312 }
1313 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001314 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001315 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001316 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001317 syncSharedAccounts(userId);
1318 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001319
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001320 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001321 // Check if there's a shared account that needs to be created as an account
1322 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1323 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001324 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001325 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001326 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001327 : UserHandle.USER_SYSTEM;
1328 if (parentUserId < 0) {
1329 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1330 return;
1331 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001332 for (Account sa : sharedAccounts) {
1333 if (ArrayUtils.contains(accounts, sa)) continue;
1334 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001335 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001336 }
1337 }
1338
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001339 @Override
1340 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001341 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001342 }
1343
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001344 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001345 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001346 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001347 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1348 Log.v(TAG, "getPassword: " + account
1349 + ", caller's uid " + Binder.getCallingUid()
1350 + ", pid " + Binder.getCallingPid());
1351 }
Fred Quintana382601f2010-03-25 12:25:10 -07001352 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001353 int userId = UserHandle.getCallingUserId();
1354 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001355 String msg = String.format(
1356 "uid %s cannot get secrets for accounts of type: %s",
1357 callingUid,
1358 account.type);
1359 throw new SecurityException(msg);
1360 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001361 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001362 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001363 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001364 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001365 } finally {
1366 restoreCallingIdentity(identityToken);
1367 }
1368 }
1369
Amith Yamasani04e0d262012-02-14 11:50:53 -08001370 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001371 if (account == null) {
1372 return null;
1373 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001374 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001375 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1376 return null;
1377 }
Fred Quintana31957f12009-10-21 13:43:10 -07001378
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001379 synchronized (accounts.dbLock) {
1380 synchronized (accounts.cacheLock) {
1381 return accounts.accountsDb
1382 .findAccountPasswordByNameAndType(account.name, account.type);
1383 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001384 }
1385 }
1386
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001387 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001388 public String getPreviousName(Account account) {
1389 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1390 Log.v(TAG, "getPreviousName: " + account
1391 + ", caller's uid " + Binder.getCallingUid()
1392 + ", pid " + Binder.getCallingPid());
1393 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001394 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001395 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001396 long identityToken = clearCallingIdentity();
1397 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001398 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001399 return readPreviousNameInternal(accounts, account);
1400 } finally {
1401 restoreCallingIdentity(identityToken);
1402 }
1403 }
1404
1405 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1406 if (account == null) {
1407 return null;
1408 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001409 synchronized (accounts.dbLock) {
1410 synchronized (accounts.cacheLock) {
1411 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1412 if (previousNameRef == null) {
1413 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1414 previousNameRef = new AtomicReference<>(previousName);
1415 accounts.previousNameCache.put(account, previousNameRef);
1416 return previousName;
1417 } else {
1418 return previousNameRef.get();
1419 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001420 }
1421 }
1422 }
1423
1424 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001425 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001426 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001427 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001428 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1429 account, key, callingUid, Binder.getCallingPid());
1430 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001431 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001432 Preconditions.checkNotNull(account, "account cannot be null");
1433 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001434 int userId = UserHandle.getCallingUserId();
1435 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001436 String msg = String.format(
1437 "uid %s cannot get user data for accounts of type: %s",
1438 callingUid,
1439 account.type);
1440 throw new SecurityException(msg);
1441 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001442 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001443 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1444 return null;
1445 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001446 long identityToken = clearCallingIdentity();
1447 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001448 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001449 if (!accountExistsCache(accounts, account)) {
1450 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001451 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001452 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001453 } finally {
1454 restoreCallingIdentity(identityToken);
1455 }
1456 }
1457
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001458 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001459 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001460 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001461 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1462 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001463 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001464 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001465 + ", pid " + Binder.getCallingPid());
1466 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001467 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001468 if (isCrossUser(callingUid, userId)) {
1469 throw new SecurityException(
1470 String.format(
1471 "User %s tying to get authenticator types for %s" ,
1472 UserHandle.getCallingUserId(),
1473 userId));
1474 }
1475
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001476 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001477 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001478 return getAuthenticatorTypesInternal(userId);
1479
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001480 } finally {
1481 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001482 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001483 }
1484
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001485 /**
1486 * Should only be called inside of a clearCallingIdentity block.
1487 */
1488 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001489 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001490 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1491 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1492 AuthenticatorDescription[] types =
1493 new AuthenticatorDescription[authenticatorCollection.size()];
1494 int i = 0;
1495 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1496 : authenticatorCollection) {
1497 types[i] = authenticator.type;
1498 i++;
1499 }
1500 return types;
1501 }
1502
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001503 private boolean isCrossUser(int callingUid, int userId) {
1504 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001505 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001506 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001507 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1508 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001509 }
1510
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001511 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001512 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001513 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001514 }
1515
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001516 @Override
1517 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001518 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001519 int callingUid = Binder.getCallingUid();
1520 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1521 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001522 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001523 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001524 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1525 final UserAccounts toAccounts = getUserAccounts(userTo);
1526 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001527 if (response != null) {
1528 Bundle result = new Bundle();
1529 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1530 try {
1531 response.onResult(result);
1532 } catch (RemoteException e) {
1533 Slog.w(TAG, "Failed to report error back to the client." + e);
1534 }
1535 }
1536 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001537 }
1538
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001539 Slog.d(TAG, "Copying account " + account.name
1540 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001541 long identityToken = clearCallingIdentity();
1542 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001543 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001544 false /* stripAuthTokenFromResult */, account.name,
1545 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001546 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001547 protected String toDebugString(long now) {
1548 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1549 + ", " + account.type;
1550 }
1551
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001552 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001553 public void run() throws RemoteException {
1554 mAuthenticator.getAccountCredentialsForCloning(this, account);
1555 }
1556
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001557 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001558 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001559 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001560 if (result != null
1561 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1562 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001563 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001564 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001565 super.onResult(result);
1566 }
1567 }
1568 }.bind();
1569 } finally {
1570 restoreCallingIdentity(identityToken);
1571 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001572 }
1573
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001574 @Override
1575 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001576 final int callingUid = Binder.getCallingUid();
1577 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1578 String msg = String.format(
1579 "accountAuthenticated( account: %s, callerUid: %s)",
1580 account,
1581 callingUid);
1582 Log.v(TAG, msg);
1583 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001584 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001585 int userId = UserHandle.getCallingUserId();
1586 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001587 String msg = String.format(
1588 "uid %s cannot notify authentication for accounts of type: %s",
1589 callingUid,
1590 account.type);
1591 throw new SecurityException(msg);
1592 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001593
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001594 if (!canUserModifyAccounts(userId, callingUid) ||
1595 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001596 return false;
1597 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001598
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001599 long identityToken = clearCallingIdentity();
1600 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001601 UserAccounts accounts = getUserAccounts(userId);
1602 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001603 } finally {
1604 restoreCallingIdentity(identityToken);
1605 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001606 }
1607
1608 private boolean updateLastAuthenticatedTime(Account account) {
1609 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001610 synchronized (accounts.dbLock) {
1611 synchronized (accounts.cacheLock) {
1612 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1613 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001614 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001615 }
1616
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001617 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001618 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1619 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001620 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001621 long id = clearCallingIdentity();
1622 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001623 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001624 false /* stripAuthTokenFromResult */, account.name,
1625 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001626 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001627 protected String toDebugString(long now) {
1628 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1629 + ", " + account.type;
1630 }
1631
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001632 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001633 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001634 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001635 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1636 if (acc.equals(account)) {
1637 mAuthenticator.addAccountFromCredentials(
1638 this, account, accountCredentials);
1639 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001640 }
1641 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001642 }
1643
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001644 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001645 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001646 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001647 // TODO: Anything to do if if succedded?
1648 // TODO: If it failed: Show error notification? Should we remove the shadow
1649 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001650 // TODO: what we do with the visibility?
1651
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001652 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001653 }
1654
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001655 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001656 public void onError(int errorCode, String errorMessage) {
1657 super.onError(errorCode, errorMessage);
1658 // TODO: Show error notification to user
1659 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1660 }
1661
1662 }.bind();
1663 } finally {
1664 restoreCallingIdentity(id);
1665 }
1666 }
1667
Amith Yamasani04e0d262012-02-14 11:50:53 -08001668 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001669 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001670 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001671 if (account == null) {
1672 return false;
1673 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001674 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001675 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1676 + " is locked. callingUid=" + callingUid);
1677 return false;
1678 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001679 synchronized (accounts.dbLock) {
1680 synchronized (accounts.cacheLock) {
1681 accounts.accountsDb.beginTransaction();
1682 try {
1683 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1684 Log.w(TAG, "insertAccountIntoDatabase: " + account
1685 + ", skipping since the account already exists");
1686 return false;
1687 }
1688 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1689 if (accountId < 0) {
1690 Log.w(TAG, "insertAccountIntoDatabase: " + account
1691 + ", skipping the DB insert failed");
1692 return false;
1693 }
1694 // Insert into DE table
1695 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1696 Log.w(TAG, "insertAccountIntoDatabase: " + account
1697 + ", skipping the DB insert failed");
1698 return false;
1699 }
1700 if (extras != null) {
1701 for (String key : extras.keySet()) {
1702 final String value = extras.getString(key);
1703 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1704 Log.w(TAG, "insertAccountIntoDatabase: " + account
1705 + ", skipping since insertExtra failed for key " + key);
1706 return false;
1707 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001708 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001709 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001710
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001711 if (packageToVisibility != null) {
1712 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1713 setAccountVisibility(account, entry.getKey() /* package */,
1714 entry.getValue() /* visibility */, false /* notify */,
1715 accounts);
1716 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001717 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001718 accounts.accountsDb.setTransactionSuccessful();
1719
1720 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1721 accountId,
1722 accounts, callingUid);
1723
1724 insertAccountIntoCacheLocked(accounts, account);
1725 } finally {
1726 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001727 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001728 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001729 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001730 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1731 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001732 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001733
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001734 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001735 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1736 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001737
Amith Yamasani5be347b2013-03-31 17:44:31 -07001738 return true;
1739 }
1740
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001741 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001742 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001743 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001744 }
1745 }
1746
Amith Yamasani5be347b2013-03-31 17:44:31 -07001747 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001748 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001749 * running, then clone the account too.
1750 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001751 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001752 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001753 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001754 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001755 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001756 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001757 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001758 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001759 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001760 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001761 }
1762 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001763 }
1764 }
1765
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001766 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001767 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001768 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001769 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001770 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001771 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1772 Log.v(TAG, "hasFeatures: " + account
1773 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001774 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001775 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001776 + ", pid " + Binder.getCallingPid());
1777 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001778 Preconditions.checkArgument(account != null, "account cannot be null");
1779 Preconditions.checkArgument(response != null, "response cannot be null");
1780 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001781 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001782 checkReadAccountsPermitted(callingUid, account.type, userId,
1783 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001784
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001785 long identityToken = clearCallingIdentity();
1786 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001787 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001788 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001789 } finally {
1790 restoreCallingIdentity(identityToken);
1791 }
1792 }
1793
1794 private class TestFeaturesSession extends Session {
1795 private final String[] mFeatures;
1796 private final Account mAccount;
1797
Amith Yamasani04e0d262012-02-14 11:50:53 -08001798 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001799 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001800 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001801 true /* stripAuthTokenFromResult */, account.name,
1802 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001803 mFeatures = features;
1804 mAccount = account;
1805 }
1806
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001807 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001808 public void run() throws RemoteException {
1809 try {
1810 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1811 } catch (RemoteException e) {
1812 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1813 }
1814 }
1815
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001816 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001817 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001818 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001819 IAccountManagerResponse response = getResponseAndClose();
1820 if (response != null) {
1821 try {
1822 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001823 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001824 return;
1825 }
Fred Quintana56285a62010-12-02 14:20:51 -08001826 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1827 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1828 + response);
1829 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001830 final Bundle newResult = new Bundle();
1831 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1832 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1833 response.onResult(newResult);
1834 } catch (RemoteException e) {
1835 // if the caller is dead then there is no one to care about remote exceptions
1836 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1837 Log.v(TAG, "failure while notifying response", e);
1838 }
1839 }
1840 }
1841 }
1842
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001843 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001844 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001845 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001846 + ", " + mAccount
1847 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1848 }
1849 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001850
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001851 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001852 public void renameAccount(
1853 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001854 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001855 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1856 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001857 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001858 + ", pid " + Binder.getCallingPid());
1859 }
1860 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001861 int userId = UserHandle.getCallingUserId();
1862 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001863 String msg = String.format(
1864 "uid %s cannot rename accounts of type: %s",
1865 callingUid,
1866 accountToRename.type);
1867 throw new SecurityException(msg);
1868 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001869 long identityToken = clearCallingIdentity();
1870 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001871 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001872 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001873 Bundle result = new Bundle();
1874 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1875 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001876 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1877 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001878 try {
1879 response.onResult(result);
1880 } catch (RemoteException e) {
1881 Log.w(TAG, e.getMessage());
1882 }
1883 } finally {
1884 restoreCallingIdentity(identityToken);
1885 }
1886 }
1887
1888 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001889 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001890 Account resultAccount = null;
1891 /*
1892 * Cancel existing notifications. Let authenticators
1893 * re-post notifications as required. But we don't know if
1894 * the authenticators have bound their notifications to
1895 * now stale account name data.
1896 *
1897 * With a rename api, we might not need to do this anymore but it
1898 * shouldn't hurt.
1899 */
1900 cancelNotification(
1901 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04001902 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001903 synchronized(accounts.credentialsPermissionNotificationIds) {
1904 for (Pair<Pair<Account, String>, Integer> pair:
1905 accounts.credentialsPermissionNotificationIds.keySet()) {
1906 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04001907 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001908 cancelNotification(id, new UserHandle(accounts.userId));
1909 }
1910 }
1911 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001912 synchronized (accounts.dbLock) {
1913 synchronized (accounts.cacheLock) {
1914 accounts.accountsDb.beginTransaction();
1915 Account renamedAccount = new Account(newName, accountToRename.type);
1916 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1917 Log.e(TAG, "renameAccount failed - account with new name already exists");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001918 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001919 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001920 try {
1921 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
1922 if (accountId >= 0) {
1923 accounts.accountsDb.renameCeAccount(accountId, newName);
1924 if (accounts.accountsDb.renameDeAccount(
1925 accountId, newName, accountToRename.name)) {
1926 accounts.accountsDb.setTransactionSuccessful();
1927 } else {
1928 Log.e(TAG, "renameAccount failed");
1929 return null;
1930 }
1931 } else {
1932 Log.e(TAG, "renameAccount failed - old account does not exist");
1933 return null;
1934 }
1935 } finally {
1936 accounts.accountsDb.endTransaction();
1937 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001938 /*
1939 * Database transaction was successful. Clean up cached
1940 * data associated with the account in the user profile.
1941 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001942 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001943 /*
1944 * Extract the data and token caches before removing the
1945 * old account to preserve the user data associated with
1946 * the account.
1947 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001948 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1949 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
1950 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
1951 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001952 /*
1953 * Update the cached data associated with the renamed
1954 * account.
1955 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001956 accounts.userDataCache.put(renamedAccount, tmpData);
1957 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1958 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
1959 accounts.previousNameCache.put(
1960 renamedAccount,
1961 new AtomicReference<>(accountToRename.name));
1962 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001963
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001964 int parentUserId = accounts.userId;
1965 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001966 /*
1967 * Owner or system user account was renamed, rename the account for
1968 * those users with which the account was shared.
1969 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001970 List<UserInfo> users = getUserManager().getUsers(true);
1971 for (UserInfo user : users) {
1972 if (user.isRestricted()
1973 && (user.restrictedProfileParentId == parentUserId)) {
1974 renameSharedAccountAsUser(accountToRename, newName, user.id);
1975 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001976 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001977 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001978
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001979 sendNotificationAccountUpdated(resultAccount, accounts);
1980 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001981 sendAccountRemovedBroadcast(accounts.userId);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001982 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001983 }
1984 return resultAccount;
1985 }
1986
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001987 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001988 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001989 return userInfo != null && userInfo.canHaveProfile();
1990 }
1991
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001992 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001993 public void removeAccount(IAccountManagerResponse response, Account account,
1994 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001995 removeAccountAsUser(
1996 response,
1997 account,
1998 expectActivityLaunch,
1999 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002000 }
2001
2002 @Override
2003 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002004 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002005 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002006 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2007 Log.v(TAG, "removeAccount: " + account
2008 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002009 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002010 + ", pid " + Binder.getCallingPid()
2011 + ", for user id " + userId);
2012 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002013 Preconditions.checkArgument(account != null, "account cannot be null");
2014 Preconditions.checkArgument(response != null, "response cannot be null");
2015
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002016 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002017 if (isCrossUser(callingUid, userId)) {
2018 throw new SecurityException(
2019 String.format(
2020 "User %s tying remove account for %s" ,
2021 UserHandle.getCallingUserId(),
2022 userId));
2023 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002024 /*
2025 * Only the system or authenticator should be allowed to remove accounts for that
2026 * authenticator. This will let users remove accounts (via Settings in the system) but not
2027 * arbitrary applications (like competing authenticators).
2028 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002029 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002030 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
2031 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002032 String msg = String.format(
2033 "uid %s cannot remove accounts of type: %s",
2034 callingUid,
2035 account.type);
2036 throw new SecurityException(msg);
2037 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002038 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002039 try {
2040 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2041 "User cannot modify accounts");
2042 } catch (RemoteException re) {
2043 }
2044 return;
2045 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002046 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002047 try {
2048 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2049 "User cannot modify accounts of this type (policy).");
2050 } catch (RemoteException re) {
2051 }
2052 return;
2053 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002054 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002055 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002056 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002057 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002058 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002059 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002060 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002061 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002062 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002063 }
2064 }
2065 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002066 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002067 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002068 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2069 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002070 accountId,
2071 accounts,
2072 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002073 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002074 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2075 } finally {
2076 restoreCallingIdentity(identityToken);
2077 }
2078 }
2079
2080 @Override
2081 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002082 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002083 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2084 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002085 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002086 + ", pid " + Binder.getCallingPid());
2087 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002088 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002089 if (account == null) {
2090 /*
2091 * Null accounts should result in returning false, as per
2092 * AccountManage.addAccountExplicitly(...) java doc.
2093 */
2094 Log.e(TAG, "account is null");
2095 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002096 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002097 String msg = String.format(
2098 "uid %s cannot explicitly add accounts of type: %s",
2099 callingUid,
2100 account.type);
2101 throw new SecurityException(msg);
2102 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002103 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002104 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002105 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002106 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2107 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002108 accountId,
2109 accounts,
2110 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002111 long identityToken = clearCallingIdentity();
2112 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002113 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002114 } finally {
2115 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002116 }
Fred Quintana60307342009-03-24 22:48:12 -07002117 }
2118
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002119 private class RemoveAccountSession extends Session {
2120 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002121 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002122 Account account, boolean expectActivityLaunch) {
2123 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002124 true /* stripAuthTokenFromResult */, account.name,
2125 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002126 mAccount = account;
2127 }
2128
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002129 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002130 protected String toDebugString(long now) {
2131 return super.toDebugString(now) + ", removeAccount"
2132 + ", account " + mAccount;
2133 }
2134
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002135 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002136 public void run() throws RemoteException {
2137 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2138 }
2139
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002140 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002141 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002142 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002143 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2144 && !result.containsKey(AccountManager.KEY_INTENT)) {
2145 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002146 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002147 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002148 }
2149 IAccountManagerResponse response = getResponseAndClose();
2150 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002151 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2152 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2153 + response);
2154 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002155 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002156 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002157 try {
2158 response.onResult(result2);
2159 } catch (RemoteException e) {
2160 // ignore
2161 }
2162 }
2163 }
2164 super.onResult(result);
2165 }
2166 }
2167
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002168 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002169 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002170 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002171 }
2172
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002173 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002174 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002175 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002176 if (!userUnlocked) {
2177 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2178 + " is still locked. CE data will be removed later");
2179 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002180 synchronized (accounts.dbLock) {
2181 synchronized (accounts.cacheLock) {
2182 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2183 accounts);
2184 accounts.accountsDb.beginTransaction();
2185 // Set to a dummy value, this will only be used if the database
2186 // transaction succeeds.
2187 long accountId = -1;
2188 try {
2189 accountId = accounts.accountsDb.findDeAccountId(account);
2190 if (accountId >= 0) {
2191 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002192 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002193 // always delete from CE table if CE storage is available
2194 // DE account could be removed while CE was locked
2195 if (userUnlocked) {
2196 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2197 if (ceAccountId >= 0) {
2198 accounts.accountsDb.deleteCeAccount(ceAccountId);
2199 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002200 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002201 accounts.accountsDb.setTransactionSuccessful();
2202 } finally {
2203 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002204 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002205 if (isChanged) {
2206 removeAccountFromCacheLocked(accounts, account);
2207 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2208 .entrySet()) {
2209 if (packageToVisibility.getValue()
2210 != AccountManager.VISIBILITY_NOT_VISIBLE) {
2211 notifyPackage(packageToVisibility.getKey(), accounts);
2212 }
2213 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002214
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002215 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2216 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07002217 sendAccountRemovedBroadcast(accounts.userId);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002218 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2219 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2220 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2221 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002222 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002223 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002224 long id = Binder.clearCallingIdentity();
2225 try {
2226 int parentUserId = accounts.userId;
2227 if (canHaveProfile(parentUserId)) {
2228 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002229 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002230 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002231 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002232 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002233 }
2234 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002235 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002236 } finally {
2237 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002238 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002239
2240 if (isChanged) {
2241 synchronized (accounts.credentialsPermissionNotificationIds) {
2242 for (Pair<Pair<Account, String>, Integer> key
2243 : accounts.credentialsPermissionNotificationIds.keySet()) {
2244 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002245 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002246 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002247 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002248 account, uid, false));
2249 }
2250 }
2251 }
2252 }
2253
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002254 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002255 }
2256
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002257 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002258 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002259 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002260 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2261 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002262 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2263 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002264 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002265 + ", pid " + Binder.getCallingPid());
2266 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002267 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002268 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002269 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002270 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002271 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002272 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002273 accounts.accountsDb.beginTransaction();
2274 try {
2275 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2276 accounts.accountsDb.setTransactionSuccessful();
2277 } finally {
2278 accounts.accountsDb.endTransaction();
2279 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002280 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002281 for (Pair<Account, String> tokenInfo : deletedTokens) {
2282 Account act = tokenInfo.first;
2283 String tokenType = tokenInfo.second;
2284 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002285 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002286 // wipe out cached token in memory.
2287 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002288 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002289 }
Fred Quintana60307342009-03-24 22:48:12 -07002290 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002291 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002292 }
2293 }
2294
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002295 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002296 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002297 // TODO Move to AccountsDB
2298 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002299 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002300
Fred Quintana33269202009-04-20 16:05:10 -07002301 try {
2302 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002303 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002304 String accountName = cursor.getString(1);
2305 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002306 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002307 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002308 }
Fred Quintana33269202009-04-20 16:05:10 -07002309 } finally {
2310 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002311 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002312 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002313 }
2314
Carlos Valdivia91979be2015-05-22 14:11:35 -07002315 private void saveCachedToken(
2316 UserAccounts accounts,
2317 Account account,
2318 String callerPkg,
2319 byte[] callerSigDigest,
2320 String tokenType,
2321 String token,
2322 long expiryMillis) {
2323
2324 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2325 return;
2326 }
2327 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002328 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002329 synchronized (accounts.cacheLock) {
2330 accounts.accountTokenCaches.put(
2331 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002332 }
2333 }
2334
Amith Yamasani04e0d262012-02-14 11:50:53 -08002335 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2336 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002337 if (account == null || type == null) {
2338 return false;
2339 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002340 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002341 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002342 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002343 accounts.accountsDb.beginTransaction();
2344 boolean updateCache = false;
2345 try {
2346 long accountId = accounts.accountsDb.findDeAccountId(account);
2347 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002348 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002349 }
2350 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2351 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2352 accounts.accountsDb.setTransactionSuccessful();
2353 updateCache = true;
2354 return true;
2355 }
2356 return false;
2357 } finally {
2358 accounts.accountsDb.endTransaction();
2359 if (updateCache) {
2360 synchronized (accounts.cacheLock) {
2361 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2362 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002363 }
Fred Quintana33269202009-04-20 16:05:10 -07002364 }
Fred Quintana60307342009-03-24 22:48:12 -07002365 }
2366 }
2367
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002368 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002369 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002370 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002371 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2372 Log.v(TAG, "peekAuthToken: " + account
2373 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002374 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002375 + ", pid " + Binder.getCallingPid());
2376 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002377 Preconditions.checkNotNull(account, "account cannot be null");
2378 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002379 int userId = UserHandle.getCallingUserId();
2380 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002381 String msg = String.format(
2382 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2383 callingUid,
2384 account.type);
2385 throw new SecurityException(msg);
2386 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002387 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002388 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2389 + callingUid);
2390 return null;
2391 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002392 long identityToken = clearCallingIdentity();
2393 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002394 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002395 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002396 } finally {
2397 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002398 }
Fred Quintana60307342009-03-24 22:48:12 -07002399 }
2400
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002401 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002402 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002403 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002404 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2405 Log.v(TAG, "setAuthToken: " + account
2406 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002407 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002408 + ", pid " + Binder.getCallingPid());
2409 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002410 Preconditions.checkNotNull(account, "account cannot be null");
2411 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002412 int userId = UserHandle.getCallingUserId();
2413 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002414 String msg = String.format(
2415 "uid %s cannot set auth tokens associated with accounts of type: %s",
2416 callingUid,
2417 account.type);
2418 throw new SecurityException(msg);
2419 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002420 long identityToken = clearCallingIdentity();
2421 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002422 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002423 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002424 } finally {
2425 restoreCallingIdentity(identityToken);
2426 }
Fred Quintana60307342009-03-24 22:48:12 -07002427 }
2428
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002429 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002430 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002431 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002432 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2433 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002434 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002435 + ", pid " + Binder.getCallingPid());
2436 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002437 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002438 int userId = UserHandle.getCallingUserId();
2439 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002440 String msg = String.format(
2441 "uid %s cannot set secrets for accounts of type: %s",
2442 callingUid,
2443 account.type);
2444 throw new SecurityException(msg);
2445 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002446 long identityToken = clearCallingIdentity();
2447 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002448 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002449 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002450 } finally {
2451 restoreCallingIdentity(identityToken);
2452 }
Fred Quintana60307342009-03-24 22:48:12 -07002453 }
2454
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002455 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2456 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002457 if (account == null) {
2458 return;
2459 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002460 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002461 synchronized (accounts.dbLock) {
2462 synchronized (accounts.cacheLock) {
2463 accounts.accountsDb.beginTransaction();
2464 try {
2465 final long accountId = accounts.accountsDb.findDeAccountId(account);
2466 if (accountId >= 0) {
2467 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2468 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2469 accounts.authTokenCache.remove(account);
2470 accounts.accountTokenCaches.remove(account);
2471 accounts.accountsDb.setTransactionSuccessful();
2472 // If there is an account whose password will be updated and the database
2473 // transactions succeed, then we say that a change has occured. Even if the
2474 // new password is the same as the old and there were no authtokens to
2475 // delete.
2476 isChanged = true;
2477 String action = (password == null || password.length() == 0) ?
2478 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2479 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2480 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2481 callingUid);
2482 }
2483 } finally {
2484 accounts.accountsDb.endTransaction();
2485 if (isChanged) {
2486 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2487 sendNotificationAccountUpdated(account, accounts);
2488 sendAccountsChangedBroadcast(accounts.userId);
2489 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002490 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002491 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002492 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002493 }
2494
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002495 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002496 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002497 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002498 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2499 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002500 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002501 + ", pid " + Binder.getCallingPid());
2502 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002503 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002504 int userId = UserHandle.getCallingUserId();
2505 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002506 String msg = String.format(
2507 "uid %s cannot clear passwords for accounts of type: %s",
2508 callingUid,
2509 account.type);
2510 throw new SecurityException(msg);
2511 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002512 long identityToken = clearCallingIdentity();
2513 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002514 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002515 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002516 } finally {
2517 restoreCallingIdentity(identityToken);
2518 }
Fred Quintana60307342009-03-24 22:48:12 -07002519 }
2520
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002521 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002522 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002523 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002524 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2525 Log.v(TAG, "setUserData: " + account
2526 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002527 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002528 + ", pid " + Binder.getCallingPid());
2529 }
Fred Quintana382601f2010-03-25 12:25:10 -07002530 if (key == null) throw new IllegalArgumentException("key is null");
2531 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002532 int userId = UserHandle.getCallingUserId();
2533 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002534 String msg = String.format(
2535 "uid %s cannot set user data for accounts of type: %s",
2536 callingUid,
2537 account.type);
2538 throw new SecurityException(msg);
2539 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002540 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002541 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002542 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002543 if (!accountExistsCache(accounts, account)) {
2544 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002545 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002546 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002547 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002548 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002549 }
2550 }
2551
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002552 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2553 synchronized (accounts.cacheLock) {
2554 if (accounts.accountCache.containsKey(account.type)) {
2555 for (Account acc : accounts.accountCache.get(account.type)) {
2556 if (acc.name.equals(account.name)) {
2557 return true;
2558 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002559 }
2560 }
2561 }
2562 return false;
2563 }
2564
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002565 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002566 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002567 synchronized (accounts.dbLock) {
2568 accounts.accountsDb.beginTransaction();
2569 try {
2570 long accountId = accounts.accountsDb.findDeAccountId(account);
2571 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002572 return;
2573 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002574 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2575 if (extrasId < 0) {
2576 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2577 if (extrasId < 0) {
2578 return;
2579 }
2580 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2581 return;
2582 }
2583 accounts.accountsDb.setTransactionSuccessful();
2584 } finally {
2585 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002586 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002587 synchronized (accounts.cacheLock) {
2588 writeUserDataIntoCacheLocked(accounts, account, key, value);
2589 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002590 }
2591 }
2592
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002593 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002594 if (result == null) {
2595 Log.e(TAG, "the result is unexpectedly null", new Exception());
2596 }
2597 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2598 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2599 + response);
2600 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002601 try {
2602 response.onResult(result);
2603 } catch (RemoteException e) {
2604 // if the caller is dead then there is no one to care about remote
2605 // exceptions
2606 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2607 Log.v(TAG, "failure while notifying response", e);
2608 }
2609 }
2610 }
2611
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002612 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002613 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2614 final String authTokenType)
2615 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002616 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2617 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002618
Fred Quintanad9640ec2012-05-23 12:37:00 -07002619 final int callingUid = getCallingUid();
2620 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002621 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002622 throw new SecurityException("can only call from system");
2623 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002624 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002625 long identityToken = clearCallingIdentity();
2626 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002627 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002628 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2629 false /* stripAuthTokenFromResult */, null /* accountName */,
2630 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002631 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002632 protected String toDebugString(long now) {
2633 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002634 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002635 + ", authTokenType " + authTokenType;
2636 }
2637
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002638 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002639 public void run() throws RemoteException {
2640 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2641 }
2642
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002643 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002644 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002645 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002646 if (result != null) {
2647 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2648 Bundle bundle = new Bundle();
2649 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2650 super.onResult(bundle);
2651 return;
2652 } else {
2653 super.onResult(result);
2654 }
2655 }
2656 }.bind();
2657 } finally {
2658 restoreCallingIdentity(identityToken);
2659 }
2660 }
2661
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002662 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002663 public void getAuthToken(
2664 IAccountManagerResponse response,
2665 final Account account,
2666 final String authTokenType,
2667 final boolean notifyOnAuthFailure,
2668 final boolean expectActivityLaunch,
2669 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002670 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002671 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2672 Log.v(TAG, "getAuthToken: " + account
2673 + ", response " + response
2674 + ", authTokenType " + authTokenType
2675 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2676 + ", expectActivityLaunch " + expectActivityLaunch
2677 + ", caller's uid " + Binder.getCallingUid()
2678 + ", pid " + Binder.getCallingPid());
2679 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002680 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002681 try {
2682 if (account == null) {
2683 Slog.w(TAG, "getAuthToken called with null account");
2684 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2685 return;
2686 }
2687 if (authTokenType == null) {
2688 Slog.w(TAG, "getAuthToken called with null authTokenType");
2689 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2690 return;
2691 }
2692 } catch (RemoteException e) {
2693 Slog.w(TAG, "Failed to report error back to the client." + e);
2694 return;
2695 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002696 int userId = UserHandle.getCallingUserId();
2697 long ident = Binder.clearCallingIdentity();
2698 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002699 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002700 try {
2701 accounts = getUserAccounts(userId);
2702 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2703 AuthenticatorDescription.newKey(account.type), accounts.userId);
2704 } finally {
2705 Binder.restoreCallingIdentity(ident);
2706 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002707
Costin Manolachea40c6302010-12-13 14:50:45 -08002708 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002709 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002710
2711 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002712 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002713 final boolean permissionGranted =
2714 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002715
Carlos Valdivia91979be2015-05-22 14:11:35 -07002716 // Get the calling package. We will use it for the purpose of caching.
2717 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002718 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002719 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002720 try {
2721 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2722 } finally {
2723 Binder.restoreCallingIdentity(ident);
2724 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002725 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2726 String msg = String.format(
2727 "Uid %s is attempting to illegally masquerade as package %s!",
2728 callerUid,
2729 callerPkg);
2730 throw new SecurityException(msg);
2731 }
2732
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002733 // let authenticator know the identity of the caller
2734 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2735 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002736
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002737 if (notifyOnAuthFailure) {
2738 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002739 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002740
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002741 long identityToken = clearCallingIdentity();
2742 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002743 // Distill the caller's package signatures into a single digest.
2744 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2745
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002746 // if the caller has permission, do the peek. otherwise go the more expensive
2747 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002748 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002749 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002750 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002751 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002752 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2753 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2754 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002755 onResult(response, result);
2756 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002757 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002758 }
2759
Carlos Valdivia91979be2015-05-22 14:11:35 -07002760 if (customTokens) {
2761 /*
2762 * Look up tokens in the new cache only if the loginOptions don't have parameters
2763 * outside of those expected to be injected by the AccountManager, e.g.
2764 * ANDORID_PACKAGE_NAME.
2765 */
2766 String token = readCachedTokenInternal(
2767 accounts,
2768 account,
2769 authTokenType,
2770 callerPkg,
2771 callerPkgSigDigest);
2772 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002773 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2774 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2775 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002776 Bundle result = new Bundle();
2777 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2778 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2779 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2780 onResult(response, result);
2781 return;
2782 }
2783 }
2784
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002785 new Session(
2786 accounts,
2787 response,
2788 account.type,
2789 expectActivityLaunch,
2790 false /* stripAuthTokenFromResult */,
2791 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002792 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002793 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002794 protected String toDebugString(long now) {
2795 if (loginOptions != null) loginOptions.keySet();
2796 return super.toDebugString(now) + ", getAuthToken"
2797 + ", " + account
2798 + ", authTokenType " + authTokenType
2799 + ", loginOptions " + loginOptions
2800 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2801 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002802
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002803 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002804 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002805 // If the caller doesn't have permission then create and return the
2806 // "grant permission" intent instead of the "getAuthToken" intent.
2807 if (!permissionGranted) {
2808 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2809 } else {
2810 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2811 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002812 }
2813
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002814 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002815 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002816 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002817 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002818 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002819 Intent intent = newGrantCredentialsPermissionIntent(
2820 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002821 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002822 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002823 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002824 authTokenType,
2825 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002826 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002827 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002828 onResult(bundle);
2829 return;
2830 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002831 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002832 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002833 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2834 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002835 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002836 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002837 "the type and name should not be empty");
2838 return;
2839 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002840 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002841 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002842 saveAuthTokenToDatabase(
2843 mAccounts,
2844 resultAccount,
2845 authTokenType,
2846 authToken);
2847 }
2848 long expiryMillis = result.getLong(
2849 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2850 if (customTokens
2851 && expiryMillis > System.currentTimeMillis()) {
2852 saveCachedToken(
2853 mAccounts,
2854 account,
2855 callerPkg,
2856 callerPkgSigDigest,
2857 authTokenType,
2858 authToken,
2859 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002860 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002861 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002862
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002863 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002864 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002865 /*
2866 * Make sure that the supplied intent is owned by the authenticator
2867 * giving it to the system. Otherwise a malicious authenticator could
2868 * have users launching arbitrary activities by tricking users to
2869 * interact with malicious notifications.
2870 */
2871 checkKeyIntent(
2872 Binder.getCallingUid(),
2873 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002874 doNotification(
2875 mAccounts,
2876 account,
2877 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002878 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002879 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002880 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002881 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002882 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002883 }.bind();
2884 } finally {
2885 restoreCallingIdentity(identityToken);
2886 }
Fred Quintana60307342009-03-24 22:48:12 -07002887 }
2888
Carlos Valdivia91979be2015-05-22 14:11:35 -07002889 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2890 MessageDigest digester;
2891 try {
2892 digester = MessageDigest.getInstance("SHA-256");
2893 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2894 callerPkg, PackageManager.GET_SIGNATURES);
2895 for (Signature sig : pkgInfo.signatures) {
2896 digester.update(sig.toByteArray());
2897 }
2898 } catch (NoSuchAlgorithmException x) {
2899 Log.wtf(TAG, "SHA-256 should be available", x);
2900 digester = null;
2901 } catch (NameNotFoundException e) {
2902 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2903 digester = null;
2904 }
2905 return (digester == null) ? null : digester.digest();
2906 }
2907
Dianne Hackborn41203752012-08-31 14:05:51 -07002908 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002909 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002910 int uid = intent.getIntExtra(
2911 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2912 String authTokenType = intent.getStringExtra(
2913 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002914 final String titleAndSubtitle =
2915 mContext.getString(R.string.permission_request_notification_with_subtitle,
2916 account.name);
2917 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002918 String title = titleAndSubtitle;
2919 String subtitle = "";
2920 if (index > 0) {
2921 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002922 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002923 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002924 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002925 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05002926 Notification n =
2927 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
2928 .setSmallIcon(android.R.drawable.stat_sys_warning)
2929 .setWhen(0)
2930 .setColor(contextForUser.getColor(
2931 com.android.internal.R.color.system_notification_accent_color))
2932 .setContentTitle(title)
2933 .setContentText(subtitle)
2934 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2935 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2936 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002937 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002938 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002939 }
2940
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002941 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2942 int uid, AccountAuthenticatorResponse response, String authTokenType,
2943 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002944
2945 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002946
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002947 if (startInNewTask) {
2948 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2949 // Since it was set in Eclair+ we can't change it without breaking apps using
2950 // the intent from a non-Activity context. This is the default behavior.
2951 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2952 }
Chris Wren717a8812017-03-31 15:34:39 -04002953 intent.addCategory(getCredentialPermissionNotificationId(account,
2954 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002955 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002956 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2957 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002958 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002959
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002960 return intent;
2961 }
2962
Chris Wren717a8812017-03-31 15:34:39 -04002963 private NotificationId getCredentialPermissionNotificationId(Account account,
2964 String authTokenType, int uid) {
2965 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002966 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002967 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002968 final Pair<Pair<Account, String>, Integer> key =
2969 new Pair<Pair<Account, String>, Integer>(
2970 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04002971 nId = accounts.credentialsPermissionNotificationIds.get(key);
2972 if (nId == null) {
2973 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
2974 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
2975 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
2976 nId = new NotificationId(tag, id);
2977 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002978 }
2979 }
Chris Wren717a8812017-03-31 15:34:39 -04002980 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002981 }
2982
Chris Wren717a8812017-03-31 15:34:39 -04002983 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
2984 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002985 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04002986 nId = accounts.signinRequiredNotificationIds.get(account);
2987 if (nId == null) {
2988 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
2989 + ":" + account.hashCode();
2990 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
2991 nId = new NotificationId(tag, id);
2992 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002993 }
2994 }
Chris Wren717a8812017-03-31 15:34:39 -04002995 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002996 }
2997
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002998 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002999 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003000 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003001 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003002 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003003 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3004 Log.v(TAG, "addAccount: accountType " + accountType
3005 + ", response " + response
3006 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003007 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003008 + ", expectActivityLaunch " + expectActivityLaunch
3009 + ", caller's uid " + Binder.getCallingUid()
3010 + ", pid " + Binder.getCallingPid());
3011 }
Fred Quintana382601f2010-03-25 12:25:10 -07003012 if (response == null) throw new IllegalArgumentException("response is null");
3013 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003014
Amith Yamasani71e6c692013-03-24 17:39:28 -07003015 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003016 final int uid = Binder.getCallingUid();
3017 final int userId = UserHandle.getUserId(uid);
3018 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003019 try {
3020 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3021 "User is not allowed to add an account!");
3022 } catch (RemoteException re) {
3023 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003024 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003025 return;
3026 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003027 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003028 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003029 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3030 "User cannot modify accounts of this type (policy).");
3031 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003032 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003033 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3034 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003035 return;
3036 }
3037
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003038 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003039 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3040 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3041 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3042
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003043 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003044 long identityToken = clearCallingIdentity();
3045 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003046 UserAccounts accounts = getUserAccounts(usrId);
3047 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003048 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3049 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003050 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003051 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003052 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003053 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003054 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003055 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003056 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003057 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003058
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003059 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003060 protected String toDebugString(long now) {
3061 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003062 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003063 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003064 }
3065 }.bind();
3066 } finally {
3067 restoreCallingIdentity(identityToken);
3068 }
Fred Quintana60307342009-03-24 22:48:12 -07003069 }
3070
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003071 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003072 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3073 final String authTokenType, final String[] requiredFeatures,
3074 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003075 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003076 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003077 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3078 Log.v(TAG, "addAccount: accountType " + accountType
3079 + ", response " + response
3080 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003081 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003082 + ", expectActivityLaunch " + expectActivityLaunch
3083 + ", caller's uid " + Binder.getCallingUid()
3084 + ", pid " + Binder.getCallingPid()
3085 + ", for user id " + userId);
3086 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003087 Preconditions.checkArgument(response != null, "response cannot be null");
3088 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003089 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003090 if (isCrossUser(callingUid, userId)) {
3091 throw new SecurityException(
3092 String.format(
3093 "User %s trying to add account for %s" ,
3094 UserHandle.getCallingUserId(),
3095 userId));
3096 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003097
3098 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003099 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003100 try {
3101 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3102 "User is not allowed to add an account!");
3103 } catch (RemoteException re) {
3104 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003105 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003106 return;
3107 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003108 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003109 try {
3110 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3111 "User cannot modify accounts of this type (policy).");
3112 } catch (RemoteException re) {
3113 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003114 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3115 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003116 return;
3117 }
3118
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003119 final int pid = Binder.getCallingPid();
3120 final int uid = Binder.getCallingUid();
3121 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3122 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3123 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3124
3125 long identityToken = clearCallingIdentity();
3126 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003127 UserAccounts accounts = getUserAccounts(userId);
3128 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003129 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3130 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003131 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003132 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003133 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003134 @Override
3135 public void run() throws RemoteException {
3136 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3137 options);
3138 }
3139
3140 @Override
3141 protected String toDebugString(long now) {
3142 return super.toDebugString(now) + ", addAccount"
3143 + ", accountType " + accountType
3144 + ", requiredFeatures "
3145 + (requiredFeatures != null
3146 ? TextUtils.join(",", requiredFeatures)
3147 : null);
3148 }
3149 }.bind();
3150 } finally {
3151 restoreCallingIdentity(identityToken);
3152 }
3153 }
3154
Sandra Kwan78812282015-11-04 11:19:47 -08003155 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003156 public void startAddAccountSession(
3157 final IAccountManagerResponse response,
3158 final String accountType,
3159 final String authTokenType,
3160 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003161 final boolean expectActivityLaunch,
3162 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003163 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003164 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3165 Log.v(TAG,
3166 "startAddAccountSession: accountType " + accountType
3167 + ", response " + response
3168 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003169 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003170 + ", expectActivityLaunch " + expectActivityLaunch
3171 + ", caller's uid " + Binder.getCallingUid()
3172 + ", pid " + Binder.getCallingPid());
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");
Sandra Kwan78812282015-11-04 11:19:47 -08003176
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003177 final int uid = Binder.getCallingUid();
3178 final int userId = UserHandle.getUserId(uid);
3179 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003180 try {
3181 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3182 "User is not allowed to add an account!");
3183 } catch (RemoteException re) {
3184 }
3185 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3186 return;
3187 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003188 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003189 try {
3190 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3191 "User cannot modify accounts of this type (policy).");
3192 } catch (RemoteException re) {
3193 }
3194 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3195 userId);
3196 return;
3197 }
Sandra Kwan78812282015-11-04 11:19:47 -08003198 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003199 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3200 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3201 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3202
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003203 // Check to see if the Password should be included to the caller.
3204 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3205 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003206 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003207
Sandra Kwan78812282015-11-04 11:19:47 -08003208 long identityToken = clearCallingIdentity();
3209 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003210 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003211 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3212 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003213 new StartAccountSession(
3214 accounts,
3215 response,
3216 accountType,
3217 expectActivityLaunch,
3218 null /* accountName */,
3219 false /* authDetailsRequired */,
3220 true /* updateLastAuthenticationTime */,
3221 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003222 @Override
3223 public void run() throws RemoteException {
3224 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3225 requiredFeatures, options);
3226 }
3227
3228 @Override
3229 protected String toDebugString(long now) {
3230 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3231 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3232 + accountType + ", requiredFeatures "
3233 + (requiredFeatures != null ? requiredFeaturesStr : null);
3234 }
3235 }.bind();
3236 } finally {
3237 restoreCallingIdentity(identityToken);
3238 }
3239 }
3240
3241 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3242 private abstract class StartAccountSession extends Session {
3243
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003244 private final boolean mIsPasswordForwardingAllowed;
3245
3246 public StartAccountSession(
3247 UserAccounts accounts,
3248 IAccountManagerResponse response,
3249 String accountType,
3250 boolean expectActivityLaunch,
3251 String accountName,
3252 boolean authDetailsRequired,
3253 boolean updateLastAuthenticationTime,
3254 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003255 super(accounts, response, accountType, expectActivityLaunch,
3256 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3257 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003258 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003259 }
3260
3261 @Override
3262 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003263 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003264 mNumResults++;
3265 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003266 if (result != null
3267 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003268 checkKeyIntent(
3269 Binder.getCallingUid(),
3270 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003271 }
Sandra Kwan78812282015-11-04 11:19:47 -08003272 IAccountManagerResponse response;
3273 if (mExpectActivityLaunch && result != null
3274 && result.containsKey(AccountManager.KEY_INTENT)) {
3275 response = mResponse;
3276 } else {
3277 response = getResponseAndClose();
3278 }
3279 if (response == null) {
3280 return;
3281 }
3282 if (result == null) {
3283 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3284 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3285 + response);
3286 }
3287 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3288 "null bundle returned");
3289 return;
3290 }
3291
3292 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3293 // All AccountManager error codes are greater
3294 // than 0
3295 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3296 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3297 return;
3298 }
3299
Hongming Jin368aa192016-07-29 14:29:54 -07003300 // Omit passwords if the caller isn't permitted to see them.
3301 if (!mIsPasswordForwardingAllowed) {
3302 result.remove(AccountManager.KEY_PASSWORD);
3303 }
3304
Sandra Kwan78812282015-11-04 11:19:47 -08003305 // Strip auth token from result.
3306 result.remove(AccountManager.KEY_AUTHTOKEN);
3307
3308 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3309 Log.v(TAG,
3310 getClass().getSimpleName() + " calling onResult() on response " + response);
3311 }
3312
3313 // Get the session bundle created by authenticator. The
3314 // bundle contains data necessary for finishing the session
3315 // later. The session bundle will be encrypted here and
3316 // decrypted later when trying to finish the session.
3317 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3318 if (sessionBundle != null) {
3319 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3320 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003321 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003322 Log.w(TAG, "Account type in session bundle doesn't match request.");
3323 }
3324 // Add accountType info to session bundle. This will
3325 // override any value set by authenticator.
3326 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3327
3328 // Encrypt session bundle before returning to caller.
3329 try {
3330 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3331 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3332 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3333 } catch (GeneralSecurityException e) {
3334 if (Log.isLoggable(TAG, Log.DEBUG)) {
3335 Log.v(TAG, "Failed to encrypt session bundle!", e);
3336 }
3337 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3338 "failed to encrypt session bundle");
3339 return;
3340 }
3341 }
3342
3343 sendResponse(response, result);
3344 }
3345 }
3346
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003347 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003348 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003349 @NonNull Bundle sessionBundle,
3350 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003351 Bundle appInfo,
3352 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003353 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003354 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003355 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3356 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003357 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003358 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003359 + ", caller's uid " + callingUid
3360 + ", caller's user id " + UserHandle.getCallingUserId()
3361 + ", pid " + Binder.getCallingPid()
3362 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003363 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003364 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003365 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3366 // Account type is added to it before encryption.
3367 if (sessionBundle == null || sessionBundle.size() == 0) {
3368 throw new IllegalArgumentException("sessionBundle is empty");
3369 }
3370
Dmitry Dementyev52745472016-12-02 10:27:45 -08003371 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003372 if (isCrossUser(callingUid, userId)) {
3373 throw new SecurityException(
3374 String.format(
3375 "User %s trying to finish session for %s without cross user permission",
3376 UserHandle.getCallingUserId(),
3377 userId));
3378 }
3379
Sandra Kwan0b84b452016-01-20 15:25:42 -08003380 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003381 sendErrorResponse(response,
3382 AccountManager.ERROR_CODE_USER_RESTRICTED,
3383 "User is not allowed to add an account!");
3384 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3385 return;
3386 }
3387
3388 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003389 final Bundle decryptedBundle;
3390 final String accountType;
3391 // First decrypt session bundle to get account type for checking permission.
3392 try {
3393 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3394 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3395 if (decryptedBundle == null) {
3396 sendErrorResponse(
3397 response,
3398 AccountManager.ERROR_CODE_BAD_REQUEST,
3399 "failed to decrypt session bundle");
3400 return;
3401 }
3402 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3403 // Account type cannot be null. This should not happen if session bundle was created
3404 // properly by #StartAccountSession.
3405 if (TextUtils.isEmpty(accountType)) {
3406 sendErrorResponse(
3407 response,
3408 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3409 "accountType is empty");
3410 return;
3411 }
3412
3413 // If by any chances, decryptedBundle contains colliding keys with
3414 // system info
3415 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3416 // update credentials flow, we should replace with the new values of the current call.
3417 if (appInfo != null) {
3418 decryptedBundle.putAll(appInfo);
3419 }
3420
3421 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003422 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003423 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3424 } catch (GeneralSecurityException e) {
3425 if (Log.isLoggable(TAG, Log.DEBUG)) {
3426 Log.v(TAG, "Failed to decrypt session bundle!", e);
3427 }
3428 sendErrorResponse(
3429 response,
3430 AccountManager.ERROR_CODE_BAD_REQUEST,
3431 "failed to decrypt session bundle");
3432 return;
3433 }
3434
Sandra Kwan0b84b452016-01-20 15:25:42 -08003435 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003436 sendErrorResponse(
3437 response,
3438 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3439 "User cannot modify accounts of this type (policy).");
3440 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3441 userId);
3442 return;
3443 }
3444
3445 long identityToken = clearCallingIdentity();
3446 try {
3447 UserAccounts accounts = getUserAccounts(userId);
3448 logRecordWithUid(
3449 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003450 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3451 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003452 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003453 new Session(
3454 accounts,
3455 response,
3456 accountType,
3457 expectActivityLaunch,
3458 true /* stripAuthTokenFromResult */,
3459 null /* accountName */,
3460 false /* authDetailsRequired */,
3461 true /* updateLastAuthenticationTime */) {
3462 @Override
3463 public void run() throws RemoteException {
3464 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3465 }
3466
3467 @Override
3468 protected String toDebugString(long now) {
3469 return super.toDebugString(now)
3470 + ", finishSession"
3471 + ", accountType " + accountType;
3472 }
3473 }.bind();
3474 } finally {
3475 restoreCallingIdentity(identityToken);
3476 }
3477 }
3478
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003479 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003480 final DevicePolicyManagerInternal dpmi =
3481 LocalServices.getService(DevicePolicyManagerInternal.class);
3482 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003483 if (dpmi == null) {
3484 intent = getDefaultCantAddAccountIntent(errorCode);
3485 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003486 intent = dpmi.createUserRestrictionSupportIntent(userId,
3487 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3488 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3489 intent = dpmi.createShowAdminSupportIntent(userId, false);
3490 }
3491 if (intent == null) {
3492 intent = getDefaultCantAddAccountIntent(errorCode);
3493 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003494 long identityToken = clearCallingIdentity();
3495 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003496 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003497 } finally {
3498 restoreCallingIdentity(identityToken);
3499 }
3500 }
3501
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003502 /**
3503 * Called when we don't know precisely who is preventing us from adding an account.
3504 */
3505 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3506 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3507 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3508 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3509 return cantAddAccount;
3510 }
3511
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003512 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003513 public void confirmCredentialsAsUser(
3514 IAccountManagerResponse response,
3515 final Account account,
3516 final Bundle options,
3517 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003518 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003519 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003520 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003521 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3522 Log.v(TAG, "confirmCredentials: " + account
3523 + ", response " + response
3524 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003525 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003526 + ", pid " + Binder.getCallingPid());
3527 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003528 // Only allow the system process to read accounts of other users
3529 if (isCrossUser(callingUid, userId)) {
3530 throw new SecurityException(
3531 String.format(
3532 "User %s trying to confirm account credentials for %s" ,
3533 UserHandle.getCallingUserId(),
3534 userId));
3535 }
Fred Quintana382601f2010-03-25 12:25:10 -07003536 if (response == null) throw new IllegalArgumentException("response is null");
3537 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003538 long identityToken = clearCallingIdentity();
3539 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003540 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003541 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003542 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003543 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003544 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003545 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003546 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003547 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003548 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003549 protected String toDebugString(long now) {
3550 return super.toDebugString(now) + ", confirmCredentials"
3551 + ", " + account;
3552 }
3553 }.bind();
3554 } finally {
3555 restoreCallingIdentity(identityToken);
3556 }
Fred Quintana60307342009-03-24 22:48:12 -07003557 }
3558
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003559 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003560 public void updateCredentials(IAccountManagerResponse response, final Account account,
3561 final String authTokenType, final boolean expectActivityLaunch,
3562 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003563 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003564 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3565 Log.v(TAG, "updateCredentials: " + account
3566 + ", response " + response
3567 + ", authTokenType " + authTokenType
3568 + ", expectActivityLaunch " + expectActivityLaunch
3569 + ", caller's uid " + Binder.getCallingUid()
3570 + ", pid " + Binder.getCallingPid());
3571 }
Fred Quintana382601f2010-03-25 12:25:10 -07003572 if (response == null) throw new IllegalArgumentException("response is null");
3573 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003574 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003575 long identityToken = clearCallingIdentity();
3576 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003577 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003578 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003579 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003580 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003581 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003582 public void run() throws RemoteException {
3583 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3584 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003585 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003586 protected String toDebugString(long now) {
3587 if (loginOptions != null) loginOptions.keySet();
3588 return super.toDebugString(now) + ", updateCredentials"
3589 + ", " + account
3590 + ", authTokenType " + authTokenType
3591 + ", loginOptions " + loginOptions;
3592 }
3593 }.bind();
3594 } finally {
3595 restoreCallingIdentity(identityToken);
3596 }
Fred Quintana60307342009-03-24 22:48:12 -07003597 }
3598
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003599 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003600 public void startUpdateCredentialsSession(
3601 IAccountManagerResponse response,
3602 final Account account,
3603 final String authTokenType,
3604 final boolean expectActivityLaunch,
3605 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003606 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003607 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3608 Log.v(TAG,
3609 "startUpdateCredentialsSession: " + account + ", response " + response
3610 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3611 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3612 + ", pid " + Binder.getCallingPid());
3613 }
3614 if (response == null) {
3615 throw new IllegalArgumentException("response is null");
3616 }
3617 if (account == null) {
3618 throw new IllegalArgumentException("account is null");
3619 }
Sandra Kwana578d112015-12-16 16:01:43 -08003620
3621 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003622 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003623
3624 // Check to see if the Password should be included to the caller.
3625 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3626 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003627 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003628
Sandra Kwane68c37e2015-11-12 17:11:49 -08003629 long identityToken = clearCallingIdentity();
3630 try {
3631 UserAccounts accounts = getUserAccounts(userId);
3632 new StartAccountSession(
3633 accounts,
3634 response,
3635 account.type,
3636 expectActivityLaunch,
3637 account.name,
3638 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003639 true /* updateLastCredentialTime */,
3640 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003641 @Override
3642 public void run() throws RemoteException {
3643 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3644 loginOptions);
3645 }
3646
3647 @Override
3648 protected String toDebugString(long now) {
3649 if (loginOptions != null)
3650 loginOptions.keySet();
3651 return super.toDebugString(now)
3652 + ", startUpdateCredentialsSession"
3653 + ", " + account
3654 + ", authTokenType " + authTokenType
3655 + ", loginOptions " + loginOptions;
3656 }
3657 }.bind();
3658 } finally {
3659 restoreCallingIdentity(identityToken);
3660 }
3661 }
3662
3663 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003664 public void isCredentialsUpdateSuggested(
3665 IAccountManagerResponse response,
3666 final Account account,
3667 final String statusToken) {
3668 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3669 Log.v(TAG,
3670 "isCredentialsUpdateSuggested: " + account + ", response " + response
3671 + ", caller's uid " + Binder.getCallingUid()
3672 + ", pid " + Binder.getCallingPid());
3673 }
3674 if (response == null) {
3675 throw new IllegalArgumentException("response is null");
3676 }
3677 if (account == null) {
3678 throw new IllegalArgumentException("account is null");
3679 }
3680 if (TextUtils.isEmpty(statusToken)) {
3681 throw new IllegalArgumentException("status token is empty");
3682 }
3683
Sandra Kwan390c9d22016-01-12 14:13:37 -08003684 int usrId = UserHandle.getCallingUserId();
3685 long identityToken = clearCallingIdentity();
3686 try {
3687 UserAccounts accounts = getUserAccounts(usrId);
3688 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3689 false /* stripAuthTokenFromResult */, account.name,
3690 false /* authDetailsRequired */) {
3691 @Override
3692 protected String toDebugString(long now) {
3693 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3694 + ", " + account;
3695 }
3696
3697 @Override
3698 public void run() throws RemoteException {
3699 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3700 }
3701
3702 @Override
3703 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003704 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003705 IAccountManagerResponse response = getResponseAndClose();
3706 if (response == null) {
3707 return;
3708 }
3709
3710 if (result == null) {
3711 sendErrorResponse(
3712 response,
3713 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3714 "null bundle");
3715 return;
3716 }
3717
3718 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3719 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3720 + response);
3721 }
3722 // Check to see if an error occurred. We know if an error occurred because all
3723 // error codes are greater than 0.
3724 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3725 sendErrorResponse(response,
3726 result.getInt(AccountManager.KEY_ERROR_CODE),
3727 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3728 return;
3729 }
3730 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3731 sendErrorResponse(
3732 response,
3733 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3734 "no result in response");
3735 return;
3736 }
3737 final Bundle newResult = new Bundle();
3738 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3739 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3740 sendResponse(response, newResult);
3741 }
3742 }.bind();
3743 } finally {
3744 restoreCallingIdentity(identityToken);
3745 }
3746 }
3747
3748 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003749 public void editProperties(IAccountManagerResponse response, final String accountType,
3750 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003751 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003752 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3753 Log.v(TAG, "editProperties: accountType " + accountType
3754 + ", response " + response
3755 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003756 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003757 + ", pid " + Binder.getCallingPid());
3758 }
Fred Quintana382601f2010-03-25 12:25:10 -07003759 if (response == null) throw new IllegalArgumentException("response is null");
3760 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003761 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003762 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3763 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003764 String msg = String.format(
3765 "uid %s cannot edit authenticator properites for account type: %s",
3766 callingUid,
3767 accountType);
3768 throw new SecurityException(msg);
3769 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003770 long identityToken = clearCallingIdentity();
3771 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003772 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003773 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003774 true /* stripAuthTokenFromResult */, null /* accountName */,
3775 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003776 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003777 public void run() throws RemoteException {
3778 mAuthenticator.editProperties(this, mAccountType);
3779 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003780 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003781 protected String toDebugString(long now) {
3782 return super.toDebugString(now) + ", editProperties"
3783 + ", accountType " + accountType;
3784 }
3785 }.bind();
3786 } finally {
3787 restoreCallingIdentity(identityToken);
3788 }
Fred Quintana60307342009-03-24 22:48:12 -07003789 }
3790
Amith Yamasani12747872015-12-07 14:19:49 -08003791 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003792 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3793 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003794 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003795 throw new SecurityException("Can be called only by system UID");
3796 }
3797 Preconditions.checkNotNull(account, "account cannot be null");
3798 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3799 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3800
3801 final int userId = userHandle.getIdentifier();
3802
3803 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3804
3805 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003806 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003807 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003808 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003809 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003810 return false;
3811 }
3812 }
3813
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003814 // Returns package with oldest target SDK for given UID.
3815 private String getPackageNameForUid(int uid) {
3816 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3817 if (ArrayUtils.isEmpty(packageNames)) {
3818 return null;
3819 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003820 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003821 if (packageNames.length == 1) {
3822 return packageName;
3823 }
3824 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003825 int oldestVersion = Integer.MAX_VALUE;
3826 for (String name : packageNames) {
3827 try {
3828 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3829 if (applicationInfo != null) {
3830 int version = applicationInfo.targetSdkVersion;
3831 if (version < oldestVersion) {
3832 oldestVersion = version;
3833 packageName = name;
3834 }
3835 }
3836 } catch (NameNotFoundException e) {
3837 // skip
3838 }
3839 }
3840 return packageName;
3841 }
3842
Svet Ganovf6d424f12016-09-20 20:18:53 -07003843 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3844 int uid) {
3845 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003846 packageName = getPackageNameForUid(uid);
3847 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003848 return false;
3849 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003850 }
3851
3852 // Use null token which means any token. Having a token means the package
3853 // is trusted by the authenticator, hence it is fine to access the account.
3854 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3855 return true;
3856 }
3857 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003858 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003859
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003860 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003861 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003862 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003863 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003864 }
3865
3866 @Override
3867 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3868 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003869 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003870 throw new SecurityException("Can be called only by system UID");
3871 }
3872
3873 Preconditions.checkNotNull(account, "account cannot be null");
3874 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3875 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3876
3877 final int userId = userHandle.getIdentifier();
3878
3879 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3880
3881 final int uid;
3882 try {
3883 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3884 } catch (NameNotFoundException e) {
3885 Slog.e(TAG, "Unknown package " + packageName);
3886 return null;
3887 }
3888
3889 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3890
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003891 final long identity = Binder.clearCallingIdentity();
3892 try {
3893 return PendingIntent.getActivityAsUser(
3894 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3895 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3896 null, new UserHandle(userId)).getIntentSender();
3897 } finally {
3898 Binder.restoreCallingIdentity(identity);
3899 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003900 }
3901
3902 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3903 int uid, RemoteCallback callback) {
3904 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3905 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3906 @Override
3907 public void onResult(Bundle value) throws RemoteException {
3908 handleAuthenticatorResponse(true);
3909 }
3910
3911 @Override
3912 public void onRequestContinued() {
3913 /* ignore */
3914 }
3915
3916 @Override
3917 public void onError(int errorCode, String errorMessage) throws RemoteException {
3918 handleAuthenticatorResponse(false);
3919 }
3920
3921 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3922 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003923 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003924 UserHandle.getUserHandleForUid(uid));
3925 if (callback != null) {
3926 Bundle result = new Bundle();
3927 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3928 callback.sendResult(result);
3929 }
3930 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003931 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003932 }
3933
3934 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003935 public boolean someUserHasAccount(@NonNull final Account account) {
3936 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3937 throw new SecurityException("Only system can check for accounts across users");
3938 }
3939 final long token = Binder.clearCallingIdentity();
3940 try {
3941 AccountAndUser[] allAccounts = getAllAccounts();
3942 for (int i = allAccounts.length - 1; i >= 0; i--) {
3943 if (allAccounts[i].account.equals(account)) {
3944 return true;
3945 }
3946 }
3947 return false;
3948 } finally {
3949 Binder.restoreCallingIdentity(token);
3950 }
3951 }
3952
Fred Quintana33269202009-04-20 16:05:10 -07003953 private class GetAccountsByTypeAndFeatureSession extends Session {
3954 private final String[] mFeatures;
3955 private volatile Account[] mAccountsOfType = null;
3956 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3957 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003958 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003959 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003960
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003961 public GetAccountsByTypeAndFeatureSession(
3962 UserAccounts accounts,
3963 IAccountManagerResponse response,
3964 String type,
3965 String[] features,
3966 int callingUid,
3967 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003968 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003969 true /* stripAuthTokenFromResult */, null /* accountName */,
3970 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003971 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003972 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003973 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003974 }
3975
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003976 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003977 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07003978 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
3979 mCallingUid, mPackageName, false /* include managed not visible*/);
Fred Quintana33269202009-04-20 16:05:10 -07003980 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003981 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003982 mCurrentAccount = 0;
3983
3984 checkAccount();
3985 }
3986
3987 public void checkAccount() {
3988 if (mCurrentAccount >= mAccountsOfType.length) {
3989 sendResult();
3990 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003991 }
Fred Quintana33269202009-04-20 16:05:10 -07003992
Fred Quintana29e94b82010-03-10 12:11:51 -08003993 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3994 if (accountAuthenticator == null) {
3995 // It is possible that the authenticator has died, which is indicated by
3996 // mAuthenticator being set to null. If this happens then just abort.
3997 // There is no need to send back a result or error in this case since
3998 // that already happened when mAuthenticator was cleared.
3999 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4000 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4001 + " connected to the authenticator, " + toDebugString());
4002 }
4003 return;
4004 }
Fred Quintana33269202009-04-20 16:05:10 -07004005 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004006 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004007 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004008 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004009 }
4010 }
4011
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004012 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004013 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004014 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004015 mNumResults++;
4016 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004017 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004018 return;
4019 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004020 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004021 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4022 }
4023 mCurrentAccount++;
4024 checkAccount();
4025 }
4026
4027 public void sendResult() {
4028 IAccountManagerResponse response = getResponseAndClose();
4029 if (response != null) {
4030 try {
4031 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4032 for (int i = 0; i < accounts.length; i++) {
4033 accounts[i] = mAccountsWithFeatures.get(i);
4034 }
Fred Quintana56285a62010-12-02 14:20:51 -08004035 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4036 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4037 + response);
4038 }
Fred Quintana33269202009-04-20 16:05:10 -07004039 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004040 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004041 response.onResult(result);
4042 } catch (RemoteException e) {
4043 // if the caller is dead then there is no one to care about remote exceptions
4044 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4045 Log.v(TAG, "failure while notifying response", e);
4046 }
4047 }
4048 }
4049 }
4050
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004051 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004052 protected String toDebugString(long now) {
4053 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4054 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4055 }
4056 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004057
Amith Yamasani04e0d262012-02-14 11:50:53 -08004058 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004059 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004060 * @hide
4061 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004062 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004063 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004064 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004065 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004066 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4067 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004068 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004069 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004070 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004071 long identityToken = clearCallingIdentity();
4072 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004073 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004074 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004075 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004076 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004077 opPackageName,
4078 visibleAccountTypes,
4079 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004080 } finally {
4081 restoreCallingIdentity(identityToken);
4082 }
4083 }
4084
Amith Yamasanif29f2362012-04-05 18:29:52 -07004085 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004086 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004087 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004088 * @hide
4089 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004090 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004091 public AccountAndUser[] getRunningAccounts() {
4092 final int[] runningUserIds;
4093 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004094 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004095 } catch (RemoteException e) {
4096 // Running in system_server; should never happen
4097 throw new RuntimeException(e);
4098 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004099 return getAccounts(runningUserIds);
4100 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004101
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004102 /**
4103 * Returns accounts for all users, ignores visibility values.
4104 *
4105 * @hide
4106 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004107 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004108 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004109 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004110 final int[] userIds = new int[users.size()];
4111 for (int i = 0; i < userIds.length; i++) {
4112 userIds[i] = users.get(i).id;
4113 }
4114 return getAccounts(userIds);
4115 }
4116
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004117 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004118 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004119 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004120 for (int userId : userIds) {
4121 UserAccounts userAccounts = getUserAccounts(userId);
4122 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004123 Account[] accounts = getAccountsFromCache(
4124 userAccounts,
4125 null /* type */,
4126 Binder.getCallingUid(),
4127 null /* packageName */,
4128 false /* include managed not visible*/);
4129 for (Account account : accounts) {
4130 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004131 }
4132 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004133
4134 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4135 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004136 }
4137
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004138 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004139 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004140 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004141 int callingUid = Binder.getCallingUid();
4142 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004143 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004144 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004145 }
4146
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004147 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004148 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004149 String type,
4150 int userId,
4151 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004152 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004153 String opPackageName,
4154 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004155 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004156 // Only allow the system process to read accounts of other users
4157 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004158 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004159 && mContext.checkCallingOrSelfPermission(
4160 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4161 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004162 throw new SecurityException("User " + UserHandle.getCallingUserId()
4163 + " trying to get account for " + userId);
4164 }
4165
Fred Quintana56285a62010-12-02 14:20:51 -08004166 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4167 Log.v(TAG, "getAccounts: accountType " + type
4168 + ", caller's uid " + Binder.getCallingUid()
4169 + ", pid " + Binder.getCallingPid());
4170 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004171
4172 // If the original calling app was using account choosing activity
4173 // provided by the framework or authenticator we'll passing in
4174 // the original caller's uid here, which is what should be used for filtering.
4175 List<String> managedTypes =
4176 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4177 if (packageUid != -1 &&
4178 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4179 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004180 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004181 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004182 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004183 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4184 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004185 if (visibleAccountTypes.isEmpty()
4186 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004187 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004188 } else if (visibleAccountTypes.contains(type)) {
4189 // Prune the list down to just the requested type.
4190 visibleAccountTypes = new ArrayList<>();
4191 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004192 } // else aggregate all the visible accounts (it won't matter if the
4193 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004194
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004195 long identityToken = clearCallingIdentity();
4196 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004197 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004198 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004199 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004200 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004201 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004202 visibleAccountTypes,
4203 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004204 } finally {
4205 restoreCallingIdentity(identityToken);
4206 }
4207 }
4208
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004209 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004210 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004211 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004212 int callingUid,
4213 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004214 List<String> visibleAccountTypes,
4215 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004216 ArrayList<Account> visibleAccounts = new ArrayList<>();
4217 for (String visibleType : visibleAccountTypes) {
4218 Account[] accountsForType = getAccountsFromCache(
4219 userAccounts, visibleType, callingUid, callingPackage,
4220 includeUserManagedNotVisible);
4221 if (accountsForType != null) {
4222 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004223 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004224 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004225 Account[] result = new Account[visibleAccounts.size()];
4226 for (int i = 0; i < visibleAccounts.size(); i++) {
4227 result[i] = visibleAccounts.get(i);
4228 }
4229 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004230 }
4231
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004232 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004233 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4234 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004235 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004236 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004237 for (Account account : accounts) {
4238 addSharedAccountAsUser(account, userId);
4239 }
4240 }
4241
4242 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004243 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004244 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004245 accounts.accountsDb.deleteSharedAccount(account);
4246 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004247 if (accountId < 0) {
4248 Log.w(TAG, "insertAccountIntoDatabase: " + account
4249 + ", skipping the DB insert failed");
4250 return false;
4251 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004252 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4253 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004254 return true;
4255 }
4256
4257 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004258 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4259 userId = handleIncomingUser(userId);
4260 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004261 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4262 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004263 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004264 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004265 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004266 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004267 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004268 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004269 }
4270 return r > 0;
4271 }
4272
4273 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004274 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004275 return removeSharedAccountAsUser(account, userId, getCallingUid());
4276 }
4277
4278 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004279 userId = handleIncomingUser(userId);
4280 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004281 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4282 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004283 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004284 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004285 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004286 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004287 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004288 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004289 }
4290
4291 @Override
4292 public Account[] getSharedAccountsAsUser(int userId) {
4293 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004294 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004295 synchronized (accounts.dbLock) {
4296 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4297 Account[] accountArray = new Account[accountList.size()];
4298 accountList.toArray(accountArray);
4299 return accountArray;
4300 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004301 }
4302
4303 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004304 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004305 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004306 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004307 }
4308
Amith Yamasani27db4682013-03-30 17:07:47 -07004309 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004310 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004311 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004312 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004313 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004314 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004315 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4316 + callingUid + " with uid=" + uid);
4317 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004318 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004319 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004320 }
4321
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004322 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004323 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004324 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4325 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004326 int callingUid = Binder.getCallingUid();
4327 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004328 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004329 int packageUid = -1;
4330 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004331 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4332 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004333 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004334 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004335 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004336 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004337 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4338 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004339 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004340 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004341 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004342 }
4343
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004344 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004345 public void getAccountsByFeatures(
4346 IAccountManagerResponse response,
4347 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004348 String[] features,
4349 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004350 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004351 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004352 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4353 Log.v(TAG, "getAccounts: accountType " + type
4354 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004355 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004356 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004357 + ", pid " + Binder.getCallingPid());
4358 }
Fred Quintana382601f2010-03-25 12:25:10 -07004359 if (response == null) throw new IllegalArgumentException("response is null");
4360 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004361 int userId = UserHandle.getCallingUserId();
4362
Svetoslavf3f02ac2015-09-08 14:36:35 -07004363 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4364 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004365 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004366 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004367 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004368 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004369 try {
4370 response.onResult(result);
4371 } catch (RemoteException e) {
4372 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4373 }
4374 return;
4375 }
Fred Quintana33269202009-04-20 16:05:10 -07004376 long identityToken = clearCallingIdentity();
4377 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004378 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004379 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004380 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4381 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004382 Bundle result = new Bundle();
4383 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4384 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004385 return;
4386 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004387 new GetAccountsByTypeAndFeatureSession(
4388 userAccounts,
4389 response,
4390 type,
4391 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004392 callingUid,
4393 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004394 } finally {
4395 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004396 }
4397 }
4398
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004399 @Override
4400 public void onAccountAccessed(String token) throws RemoteException {
4401 final int uid = Binder.getCallingUid();
4402 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4403 return;
4404 }
4405 final int userId = UserHandle.getCallingUserId();
4406 final long identity = Binder.clearCallingIdentity();
4407 try {
4408 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4409 if (Objects.equals(account.getAccessId(), token)) {
4410 // An app just accessed the account. At this point it knows about
4411 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004412 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004413 if (!hasAccountAccess(account, null, uid)) {
4414 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4415 uid, true);
4416 }
4417 }
4418 }
4419 } finally {
4420 Binder.restoreCallingIdentity(identity);
4421 }
4422 }
4423
Fred Quintanaa698f422009-04-08 19:14:54 -07004424 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004425 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004426 IAccountManagerResponse mResponse;
4427 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004428 final boolean mExpectActivityLaunch;
4429 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004430 final String mAccountName;
4431 // Indicates if we need to add auth details(like last credential time)
4432 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004433 // If set, we need to update the last authenticated time. This is
4434 // currently
4435 // used on
4436 // successful confirming credentials.
4437 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004438
Fred Quintana33269202009-04-20 16:05:10 -07004439 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004440 private int mNumRequestContinued = 0;
4441 private int mNumErrors = 0;
4442
Fred Quintana60307342009-03-24 22:48:12 -07004443 IAccountAuthenticator mAuthenticator = null;
4444
Fred Quintana8570f742010-02-18 10:32:54 -08004445 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004446 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004447
Amith Yamasani04e0d262012-02-14 11:50:53 -08004448 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004449 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4450 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004451 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4452 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4453 }
4454
4455 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4456 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4457 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004458 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004459 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004460 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004461 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004462 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004463 mResponse = response;
4464 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004465 mExpectActivityLaunch = expectActivityLaunch;
4466 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004467 mAccountName = accountName;
4468 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004469 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004470
Fred Quintanaa698f422009-04-08 19:14:54 -07004471 synchronized (mSessions) {
4472 mSessions.put(toString(), this);
4473 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004474 if (response != null) {
4475 try {
4476 response.asBinder().linkToDeath(this, 0 /* flags */);
4477 } catch (RemoteException e) {
4478 mResponse = null;
4479 binderDied();
4480 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004481 }
Fred Quintana60307342009-03-24 22:48:12 -07004482 }
4483
Fred Quintanaa698f422009-04-08 19:14:54 -07004484 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004485 if (mResponse == null) {
4486 // this session has already been closed
4487 return null;
4488 }
Fred Quintana60307342009-03-24 22:48:12 -07004489 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004490 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004491 return response;
4492 }
4493
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004494 /**
4495 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4496 * security policy.
4497 *
4498 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004499 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004500 * supplied entries in the system Settings app.
4501 */
4502 protected void checkKeyIntent(
4503 int authUid,
4504 Intent intent) throws SecurityException {
4505 long bid = Binder.clearCallingIdentity();
4506 try {
4507 PackageManager pm = mContext.getPackageManager();
4508 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4509 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4510 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004511 if (!isExportedSystemActivity(targetActivityInfo)
4512 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4513 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004514 String pkgName = targetActivityInfo.packageName;
4515 String activityName = targetActivityInfo.name;
4516 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4517 + "does not share a signature with the supplying authenticator (%s).";
4518 throw new SecurityException(
4519 String.format(tmpl, activityName, pkgName, mAccountType));
4520 }
4521 } finally {
4522 Binder.restoreCallingIdentity(bid);
4523 }
4524 }
4525
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004526 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4527 String className = activityInfo.name;
4528 return "android".equals(activityInfo.packageName) &&
4529 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4530 || CantAddAccountActivity.class.getName().equals(className));
4531 }
4532
Fred Quintanaa698f422009-04-08 19:14:54 -07004533 private void close() {
4534 synchronized (mSessions) {
4535 if (mSessions.remove(toString()) == null) {
4536 // the session was already closed, so bail out now
4537 return;
4538 }
4539 }
4540 if (mResponse != null) {
4541 // stop listening for response deaths
4542 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4543
4544 // clear this so that we don't accidentally send any further results
4545 mResponse = null;
4546 }
4547 cancelTimeout();
4548 unbind();
4549 }
4550
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004551 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004552 public void binderDied() {
4553 mResponse = null;
4554 close();
4555 }
4556
4557 protected String toDebugString() {
4558 return toDebugString(SystemClock.elapsedRealtime());
4559 }
4560
4561 protected String toDebugString(long now) {
4562 return "Session: expectLaunch " + mExpectActivityLaunch
4563 + ", connected " + (mAuthenticator != null)
4564 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4565 + "/" + mNumErrors + ")"
4566 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4567 }
4568
Fred Quintana60307342009-03-24 22:48:12 -07004569 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004570 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4571 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4572 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004573 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004574 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004575 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004576 }
4577 }
4578
4579 private void unbind() {
4580 if (mAuthenticator != null) {
4581 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004582 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004583 }
4584 }
4585
Fred Quintana60307342009-03-24 22:48:12 -07004586 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004587 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004588 }
4589
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004590 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004591 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004592 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004593 try {
4594 run();
4595 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004596 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004597 "remote exception");
4598 }
Fred Quintana60307342009-03-24 22:48:12 -07004599 }
4600
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004601 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004602 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004603 mAuthenticator = null;
4604 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004605 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004606 try {
4607 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4608 "disconnected");
4609 } catch (RemoteException e) {
4610 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4611 Log.v(TAG, "Session.onServiceDisconnected: "
4612 + "caught RemoteException while responding", e);
4613 }
4614 }
Fred Quintana60307342009-03-24 22:48:12 -07004615 }
4616 }
4617
Fred Quintanab839afc2009-10-14 15:57:28 -07004618 public abstract void run() throws RemoteException;
4619
Fred Quintana60307342009-03-24 22:48:12 -07004620 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004621 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004622 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004623 try {
4624 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4625 "timeout");
4626 } catch (RemoteException e) {
4627 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4628 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4629 e);
4630 }
4631 }
Fred Quintana60307342009-03-24 22:48:12 -07004632 }
4633 }
4634
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004635 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004636 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004637 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004638 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004639 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004640 if (result != null) {
4641 boolean isSuccessfulConfirmCreds = result.getBoolean(
4642 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004643 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004644 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4645 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004646 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004647 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4648 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004649 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004650 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004651 if (needUpdate || mAuthDetailsRequired) {
4652 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4653 if (needUpdate && accountPresent) {
4654 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4655 }
4656 if (mAuthDetailsRequired) {
4657 long lastAuthenticatedTime = -1;
4658 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004659 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004660 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004661 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004662 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004663 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004664 lastAuthenticatedTime);
4665 }
4666 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004667 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004668 if (result != null
4669 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004670 checkKeyIntent(
4671 Binder.getCallingUid(),
4672 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004673 }
4674 if (result != null
4675 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004676 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4677 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004678 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4679 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004680 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4681 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004682 }
Fred Quintana60307342009-03-24 22:48:12 -07004683 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004684 IAccountManagerResponse response;
4685 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004686 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004687 response = mResponse;
4688 } else {
4689 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004690 }
Fred Quintana60307342009-03-24 22:48:12 -07004691 if (response != null) {
4692 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004693 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004694 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4695 Log.v(TAG, getClass().getSimpleName()
4696 + " calling onError() on response " + response);
4697 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004698 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004699 "null bundle returned");
4700 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004701 if (mStripAuthTokenFromResult) {
4702 result.remove(AccountManager.KEY_AUTHTOKEN);
4703 }
Fred Quintana56285a62010-12-02 14:20:51 -08004704 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4705 Log.v(TAG, getClass().getSimpleName()
4706 + " calling onResult() on response " + response);
4707 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004708 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4709 (intent == null)) {
4710 // All AccountManager error codes are greater than 0
4711 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4712 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4713 } else {
4714 response.onResult(result);
4715 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004716 }
Fred Quintana60307342009-03-24 22:48:12 -07004717 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004718 // if the caller is dead then there is no one to care about remote exceptions
4719 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4720 Log.v(TAG, "failure while notifying response", e);
4721 }
Fred Quintana60307342009-03-24 22:48:12 -07004722 }
4723 }
4724 }
Fred Quintana60307342009-03-24 22:48:12 -07004725
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004726 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004727 public void onRequestContinued() {
4728 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004729 }
4730
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004731 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004732 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004733 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004734 IAccountManagerResponse response = getResponseAndClose();
4735 if (response != null) {
4736 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004737 Log.v(TAG, getClass().getSimpleName()
4738 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004739 }
4740 try {
4741 response.onError(errorCode, errorMessage);
4742 } catch (RemoteException e) {
4743 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4744 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4745 }
4746 }
4747 } else {
4748 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4749 Log.v(TAG, "Session.onError: already closed");
4750 }
Fred Quintana60307342009-03-24 22:48:12 -07004751 }
4752 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004753
4754 /**
4755 * find the component name for the authenticator and initiate a bind
4756 * if no authenticator or the bind fails then return false, otherwise return true
4757 */
4758 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004759 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4760 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4761 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004762 if (authenticatorInfo == null) {
4763 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4764 Log.v(TAG, "there is no authenticator for " + authenticatorType
4765 + ", bailing out");
4766 }
4767 return false;
4768 }
4769
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004770 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004771 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004772 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4773 + " which isn't encryption aware");
4774 return false;
4775 }
4776
Fred Quintanab839afc2009-10-14 15:57:28 -07004777 Intent intent = new Intent();
4778 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4779 intent.setComponent(authenticatorInfo.componentName);
4780 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4781 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4782 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004783 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004784 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004785 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4786 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4787 }
4788 return false;
4789 }
4790
Fred Quintanab839afc2009-10-14 15:57:28 -07004791 return true;
4792 }
Fred Quintana60307342009-03-24 22:48:12 -07004793 }
4794
Svet Ganov5d09c992016-09-07 09:57:41 -07004795 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004796 MessageHandler(Looper looper) {
4797 super(looper);
4798 }
Costin Manolache3348f142009-09-29 18:58:36 -07004799
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004800 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004801 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004802 switch (msg.what) {
4803 case MESSAGE_TIMED_OUT:
4804 Session session = (Session)msg.obj;
4805 session.onTimedOut();
4806 break;
4807
Amith Yamasani5be347b2013-03-31 17:44:31 -07004808 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004809 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004810 break;
4811
Fred Quintana60307342009-03-24 22:48:12 -07004812 default:
4813 throw new IllegalStateException("unhandled message: " + msg.what);
4814 }
4815 }
4816 }
4817
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004818 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004819 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004820 }
4821
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004822 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004823 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004824 }
4825
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004826 /*
4827 * This function receives an opened writable database.
4828 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004829 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004830 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004831 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004832 }
4833
4834 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004835 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004836 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004837 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004838 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004839
4840 class LogRecordTask implements Runnable {
4841 private final String action;
4842 private final String tableName;
4843 private final long accountId;
4844 private final UserAccounts userAccount;
4845 private final int callingUid;
4846 private final long userDebugDbInsertionPoint;
4847
4848 LogRecordTask(final String action,
4849 final String tableName,
4850 final long accountId,
4851 final UserAccounts userAccount,
4852 final int callingUid,
4853 final long userDebugDbInsertionPoint) {
4854 this.action = action;
4855 this.tableName = tableName;
4856 this.accountId = accountId;
4857 this.userAccount = userAccount;
4858 this.callingUid = callingUid;
4859 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4860 }
4861
4862 public void run() {
4863 SQLiteStatement logStatement = userAccount.statementForLogging;
4864 logStatement.bindLong(1, accountId);
4865 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004866 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004867 logStatement.bindLong(4, callingUid);
4868 logStatement.bindString(5, tableName);
4869 logStatement.bindLong(6, userDebugDbInsertionPoint);
4870 logStatement.execute();
4871 logStatement.clearBindings();
4872 }
4873 }
4874
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004875 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4876 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004877 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004878 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004879 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004880 }
4881
4882 /*
4883 * This should only be called once to compile the sql statement for logging
4884 * and to find the insertion point.
4885 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004886 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4887 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4888 .calculateDebugTableInsertionPoint();
4889 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004890 }
4891
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004892 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004893 return asBinder();
4894 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004895
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004896 /**
4897 * Searches array of arguments for the specified string
4898 * @param args array of argument strings
4899 * @param value value to search for
4900 * @return true if the value is contained in the array
4901 */
4902 private static boolean scanArgs(String[] args, String value) {
4903 if (args != null) {
4904 for (String arg : args) {
4905 if (value.equals(arg)) {
4906 return true;
4907 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004908 }
4909 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004910 return false;
4911 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004912
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004913 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004914 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004915 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004916 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004917 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004918
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004919 final List<UserInfo> users = getUserManager().getUsers();
4920 for (UserInfo user : users) {
4921 ipw.println("User " + user + ":");
4922 ipw.increaseIndent();
4923 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4924 ipw.println();
4925 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004926 }
4927 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004928
Amith Yamasani04e0d262012-02-14 11:50:53 -08004929 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4930 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004931 if (isCheckinRequest) {
4932 // This is a checkin request. *Only* upload the account types and the count of
4933 // each.
4934 synchronized (userAccounts.dbLock) {
4935 userAccounts.accountsDb.dumpDeAccountsTable(fout);
4936 }
4937 } else {
4938 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
4939 Process.SYSTEM_UID, null /* packageName */, false);
4940 fout.println("Accounts: " + accounts.length);
4941 for (Account account : accounts) {
4942 fout.println(" " + account);
4943 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004944
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004945 // Add debug information.
4946 fout.println();
4947 synchronized (userAccounts.dbLock) {
4948 userAccounts.accountsDb.dumpDebugTable(fout);
4949 }
4950 fout.println();
4951 synchronized (mSessions) {
4952 final long now = SystemClock.elapsedRealtime();
4953 fout.println("Active Sessions: " + mSessions.size());
4954 for (Session session : mSessions.values()) {
4955 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07004956 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004957 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004958
4959 fout.println();
4960 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004961 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004962 }
4963
Amith Yamasani04e0d262012-02-14 11:50:53 -08004964 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004965 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004966 long identityToken = clearCallingIdentity();
4967 try {
4968 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4969 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4970 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004971
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004972 if (intent.getComponent() != null &&
4973 GrantCredentialsPermissionActivity.class.getName().equals(
4974 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004975 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004976 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004977 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04004978 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
4979 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004980
Fred Quintana33f889a2009-09-14 17:31:26 -07004981 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004982 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004983 Notification n =
4984 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004985 .setWhen(0)
4986 .setSmallIcon(android.R.drawable.stat_sys_warning)
4987 .setColor(contextForUser.getColor(
4988 com.android.internal.R.color.system_notification_accent_color))
4989 .setContentTitle(String.format(notificationTitleFormat, account.name))
4990 .setContentText(message)
4991 .setContentIntent(PendingIntent.getActivityAsUser(
4992 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004993 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004994 .build();
Chris Wren717a8812017-03-31 15:34:39 -04004995 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004996 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004997 } finally {
4998 restoreCallingIdentity(identityToken);
4999 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005000 }
5001
Chris Wren717a8812017-03-31 15:34:39 -04005002 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005003 String packageName, int userId) {
5004 final long token = clearCallingIdentity();
5005 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005006 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005007 try {
Chris Wren717a8812017-03-31 15:34:39 -04005008 notificationManager.enqueueNotificationWithTag(packageName, packageName,
5009 id.mTag, id.mId, notification, new int[1], userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005010 } catch (RemoteException e) {
5011 /* ignore - local call */
5012 }
5013 } finally {
5014 Binder.restoreCallingIdentity(token);
5015 }
Fred Quintana56285a62010-12-02 14:20:51 -08005016 }
5017
Chris Wren717a8812017-03-31 15:34:39 -04005018 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005019 cancelNotification(id, mContext.getPackageName(), user);
5020 }
5021
Chris Wren717a8812017-03-31 15:34:39 -04005022 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005023 long identityToken = clearCallingIdentity();
5024 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005025 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04005026 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005027 } catch (RemoteException e) {
5028 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005029 } finally {
5030 restoreCallingIdentity(identityToken);
5031 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005032 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005033
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005034 private boolean isPermittedForPackage(String packageName, int uid, int userId,
5035 String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005036 final long identity = Binder.clearCallingIdentity();
5037 try {
5038 IPackageManager pm = ActivityThread.getPackageManager();
5039 for (String perm : permissions) {
5040 if (pm.checkPermission(perm, packageName, userId)
5041 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005042 // Checks runtime permission revocation.
5043 final int opCode = AppOpsManager.permissionToOpCode(perm);
5044 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5045 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5046 return true;
5047 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005048 }
5049 }
5050 } catch (RemoteException e) {
5051 /* ignore - local call */
5052 } finally {
5053 Binder.restoreCallingIdentity(identity);
5054 }
5055 return false;
5056 }
5057
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005058 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5059 for (String perm : permissions) {
5060 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5061 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5062 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5063 }
5064 final int opCode = AppOpsManager.permissionToOpCode(perm);
5065 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5066 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5067 return true;
5068 }
5069 }
5070 }
5071 return false;
5072 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005073
Amith Yamasani67df64b2012-12-14 12:09:36 -08005074 private int handleIncomingUser(int userId) {
5075 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005076 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005077 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5078 } catch (RemoteException re) {
5079 // Shouldn't happen, local.
5080 }
5081 return userId;
5082 }
5083
Christopher Tateccbf84f2013-05-08 15:25:41 -07005084 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005085 String[] packages;
5086 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005087 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005088 packages = mPackageManager.getPackagesForUid(callingUid);
5089 } finally {
5090 Binder.restoreCallingIdentity(identityToken);
5091 }
5092 if (packages == null) {
5093 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005094 return false;
5095 }
Fred Quintana7be59642009-08-24 18:29:25 -07005096 for (String name : packages) {
5097 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005098 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08005099 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08005100 && (packageInfo.applicationInfo.privateFlags
5101 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07005102 return true;
5103 }
5104 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005105 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07005106 return false;
5107 }
5108 }
5109 return false;
5110 }
5111
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005112 private boolean permissionIsGranted(
5113 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005114 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5115 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5116 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5117 }
5118 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005119 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005120
5121 if (isPrivileged(callerUid)) {
5122 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5123 Log.v(TAG, "Access to " + account + " granted calling uid "
5124 + callerUid + " privileged");
5125 }
5126 return true;
5127 }
5128 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5129 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5130 Log.v(TAG, "Access to " + account + " granted calling uid "
5131 + callerUid + " manages the account");
5132 }
5133 return true;
5134 }
5135 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5136 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5137 Log.v(TAG, "Access to " + account + " granted calling uid "
5138 + callerUid + " user granted access");
5139 }
5140 return true;
5141 }
5142
5143 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5144 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5145 }
5146
5147 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005148 }
5149
Svetoslavf3f02ac2015-09-08 14:36:35 -07005150 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5151 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005152 if (accountType == null) {
5153 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005154 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005155 return getTypesVisibleToCaller(callingUid, userId,
5156 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005157 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005158 }
5159
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005160 // Method checks visibility for applications targeing API level below {@link
5161 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005162 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005163 private boolean checkGetAccountsPermission(String packageName, int uid, int userId) {
5164 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005165 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5166 }
5167
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005168 private boolean checkReadContactsPermission(String packageName, int uid, int userId) {
5169 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS);
5170 }
5171
5172 // Heuristic to check that account type may be associated with some contacts data and
5173 // therefore READ_CONTACTS permission grants the access to account by default.
5174 private boolean accountTypeManagesContacts(String accountType, int userId) {
5175 if (accountType == null) {
5176 return false;
5177 }
5178 long identityToken = Binder.clearCallingIdentity();
5179 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5180 try {
5181 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5182 } finally {
5183 Binder.restoreCallingIdentity(identityToken);
5184 }
5185 // Check contacts related permissions for authenticator.
5186 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5187 : serviceInfos) {
5188 if (accountType.equals(serviceInfo.type.type)) {
5189 return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId,
5190 Manifest.permission.WRITE_CONTACTS);
5191 }
5192 }
5193 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005194 }
5195
5196 /**
5197 * Method checks package uid and signature with Authenticator which manages accountType.
5198 *
5199 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5200 * SIGNATURE_CHECK_MISMATCH otherwise.
5201 */
5202 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5203 if (accountType == null) {
5204 return SIGNATURE_CHECK_MISMATCH;
5205 }
5206
5207 long identityToken = Binder.clearCallingIdentity();
5208 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5209 try {
5210 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5211 } finally {
5212 Binder.restoreCallingIdentity(identityToken);
5213 }
5214 // Check for signature match with Authenticator.
5215 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5216 : serviceInfos) {
5217 if (accountType.equals(serviceInfo.type.type)) {
5218 if (serviceInfo.uid == callingUid) {
5219 return SIGNATURE_CHECK_UID_MATCH;
5220 }
5221 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5222 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5223 return SIGNATURE_CHECK_MATCH;
5224 }
5225 }
5226 }
5227 return SIGNATURE_CHECK_MISMATCH;
5228 }
5229
5230 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005231 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5232 if (accountType == null) {
5233 return false;
5234 } else {
5235 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5236 }
5237 }
5238
Svetoslavf3f02ac2015-09-08 14:36:35 -07005239 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5240 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005241 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005242 }
5243
5244 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005245 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005246 }
5247
5248 private List<String> getTypesForCaller(
5249 int callingUid, int userId, boolean isOtherwisePermitted) {
5250 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005251 long identityToken = Binder.clearCallingIdentity();
5252 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5253 try {
5254 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5255 } finally {
5256 Binder.restoreCallingIdentity(identityToken);
5257 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005258 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005259 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005260 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5261 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005262 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005263 }
5264 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005265 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005266 }
5267
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005268 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5269 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5270 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5271 if (account.name.equals(accountName)) {
5272 return true;
5273 }
5274 }
5275 }
5276 return false;
5277 }
5278
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005279 private static void checkManageUsersPermission(String message) {
5280 if (ActivityManager.checkComponentPermission(
5281 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5282 != PackageManager.PERMISSION_GRANTED) {
5283 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5284 }
5285 }
5286
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005287 private static void checkManageOrCreateUsersPermission(String message) {
5288 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5289 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5290 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5291 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5292 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5293 + message);
5294 }
5295 }
5296
Amith Yamasani04e0d262012-02-14 11:50:53 -08005297 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5298 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005299 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005300 return true;
5301 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005302 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005303 synchronized (accounts.dbLock) {
5304 synchronized (accounts.cacheLock) {
5305 long grantsCount;
5306 if (authTokenType != null) {
5307 grantsCount = accounts.accountsDb
5308 .findMatchingGrantsCount(callerUid, authTokenType, account);
5309 } else {
5310 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5311 account);
5312 }
5313 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005314
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005315 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5316 // TODO: Skip this check when running automated tests. Replace this
5317 // with a more general solution.
5318 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5319 + authTokenType + " by uid " + callerUid
5320 + " but ignoring since device is in test harness.");
5321 return true;
5322 }
5323 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005324 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005325 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005326 }
5327
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005328 private boolean isSystemUid(int callingUid) {
5329 String[] packages = null;
5330 long ident = Binder.clearCallingIdentity();
5331 try {
5332 packages = mPackageManager.getPackagesForUid(callingUid);
5333 } finally {
5334 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005335 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005336 if (packages != null) {
5337 for (String name : packages) {
5338 try {
5339 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5340 if (packageInfo != null
5341 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5342 != 0) {
5343 return true;
5344 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005345 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005346 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5347 }
5348 }
5349 } else {
5350 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005351 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005352 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005353 }
5354
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005355 /** Succeeds if any of the specified permissions are granted. */
5356 private void checkReadAccountsPermitted(
5357 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005358 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005359 int userId,
5360 String opPackageName) {
5361 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005362 String msg = String.format(
5363 "caller uid %s cannot access %s accounts",
5364 callingUid,
5365 accountType);
5366 Log.w(TAG, " " + msg);
5367 throw new SecurityException(msg);
5368 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005369 }
5370
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005371 private boolean canUserModifyAccounts(int userId, int callingUid) {
5372 // the managing app can always modify accounts
5373 if (isProfileOwner(callingUid)) {
5374 return true;
5375 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005376 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5377 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5378 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005379 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005380 return true;
5381 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005382
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005383 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5384 // the managing app can always modify accounts
5385 if (isProfileOwner(callingUid)) {
5386 return true;
5387 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005388 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5389 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005390 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005391 if (typesArray == null) {
5392 return true;
5393 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005394 for (String forbiddenType : typesArray) {
5395 if (forbiddenType.equals(accountType)) {
5396 return false;
5397 }
5398 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005399 return true;
5400 }
5401
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005402 private boolean isProfileOwner(int uid) {
5403 final DevicePolicyManagerInternal dpmi =
5404 LocalServices.getService(DevicePolicyManagerInternal.class);
5405 return (dpmi != null)
5406 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5407 }
5408
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005409 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005410 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5411 throws RemoteException {
5412 final int callingUid = getCallingUid();
5413
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005414 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005415 throw new SecurityException();
5416 }
5417
5418 if (value) {
5419 grantAppPermission(account, authTokenType, uid);
5420 } else {
5421 revokeAppPermission(account, authTokenType, uid);
5422 }
5423 }
5424
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005425 /**
5426 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5427 * <p>
5428 * Although this is public it can only be accessed via the AccountManagerService object
5429 * which is in the system. This means we don't need to protect it with permissions.
5430 * @hide
5431 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005432 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005433 if (account == null || authTokenType == null) {
5434 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005435 return;
5436 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005437 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005438 synchronized (accounts.dbLock) {
5439 synchronized (accounts.cacheLock) {
5440 long accountId = accounts.accountsDb.findDeAccountId(account);
5441 if (accountId >= 0) {
5442 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5443 }
5444 cancelNotification(
5445 getCredentialPermissionNotificationId(account, authTokenType, uid),
5446 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005447
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005448 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5449 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005450 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005451
5452 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5453 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5454 : mAppPermissionChangeListeners) {
5455 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5456 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005457 }
5458
5459 /**
5460 * Don't allow callers with the given uid permission to get credentials for
5461 * account/authTokenType.
5462 * <p>
5463 * Although this is public it can only be accessed via the AccountManagerService object
5464 * which is in the system. This means we don't need to protect it with permissions.
5465 * @hide
5466 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005467 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005468 if (account == null || authTokenType == null) {
5469 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005470 return;
5471 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005472 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005473 synchronized (accounts.dbLock) {
5474 synchronized (accounts.cacheLock) {
5475 accounts.accountsDb.beginTransaction();
5476 try {
5477 long accountId = accounts.accountsDb.findDeAccountId(account);
5478 if (accountId >= 0) {
5479 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5480 accountId, authTokenType, uid);
5481 accounts.accountsDb.setTransactionSuccessful();
5482 }
5483 } finally {
5484 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005485 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005486
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005487 cancelNotification(
5488 getCredentialPermissionNotificationId(account, authTokenType, uid),
5489 UserHandle.of(accounts.userId));
5490 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005491 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005492
5493 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5494 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5495 : mAppPermissionChangeListeners) {
5496 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5497 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005498 }
Fred Quintana56285a62010-12-02 14:20:51 -08005499
Amith Yamasani04e0d262012-02-14 11:50:53 -08005500 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5501 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005502 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005503 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005504 for (Account curAccount : oldAccountsForType) {
5505 if (!curAccount.equals(account)) {
5506 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005507 }
5508 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005509 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005510 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005511 } else {
5512 Account[] newAccountsForType = new Account[newAccountsList.size()];
5513 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005514 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005515 }
Fred Quintana56285a62010-12-02 14:20:51 -08005516 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005517 accounts.userDataCache.remove(account);
5518 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005519 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005520 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005521 }
5522
5523 /**
5524 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005525 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5526 * processes and if you will return this account to apps you should return the result.
5527 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005528 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005529 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005530 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005531 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5532 Account[] newAccountsForType = new Account[oldLength + 1];
5533 if (accountsForType != null) {
5534 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005535 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005536 String token = account.getAccessId() != null ? account.getAccessId()
5537 : UUID.randomUUID().toString();
5538 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005539 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005540 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005541 }
5542
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005543 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005544 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005545 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005546 String visibilityFilterPackage = callingPackage;
5547 if (visibilityFilterPackage == null) {
5548 visibilityFilterPackage = getPackageNameForUid(callingUid);
5549 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005550 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005551 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005552 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005553 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5554 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5555 || (includeManagedNotVisible
5556 && (visibility
5557 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5558 firstPass.put(account, visibility);
5559 }
5560 }
5561 Map<Account, Integer> secondPass =
5562 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5563
5564 Account[] filtered = new Account[secondPass.size()];
5565 filtered = secondPass.keySet().toArray(filtered);
5566 return filtered;
5567 }
5568
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005569 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005570 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005571 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005572 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005573 // first part is to filter shared accounts.
5574 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005575 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005576 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005577 return unfiltered;
5578 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005579 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005580 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005581 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005582 if (packages == null) {
5583 packages = new String[] {};
5584 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005585 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005586 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005587 // This might be a temporary way to specify a visible list
5588 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005589 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5590 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005591 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005592 return unfiltered;
5593 }
5594 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005595 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005596 if (ArrayUtils.isEmpty(sharedAccounts)) {
5597 return unfiltered;
5598 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005599 String requiredAccountType = "";
5600 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005601 // If there's an explicit callingPackage specified, check if that package
5602 // opted in to see restricted accounts.
5603 if (callingPackage != null) {
5604 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005605 if (pi != null && pi.restrictedAccountType != null) {
5606 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005607 }
5608 } else {
5609 // Otherwise check if the callingUid has a package that has opted in
5610 for (String packageName : packages) {
5611 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5612 if (pi != null && pi.restrictedAccountType != null) {
5613 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005614 break;
5615 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005616 }
5617 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005618 } catch (NameNotFoundException e) {
5619 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005620 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005621 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005622 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5623 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005624 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005625 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005626 } else {
5627 boolean found = false;
5628 for (Account shared : sharedAccounts) {
5629 if (shared.equals(account)) {
5630 found = true;
5631 break;
5632 }
5633 }
5634 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005635 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005636 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005637 }
5638 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005639 return filtered;
5640 } else {
5641 return unfiltered;
5642 }
5643 }
5644
Amith Yamasani27db4682013-03-30 17:07:47 -07005645 /*
5646 * packageName can be null. If not null, it should be used to filter out restricted accounts
5647 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005648 *
5649 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5650 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005651 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005652 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005653 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005654 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005655 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5656 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005657 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005658 Account[] accounts;
5659 synchronized (userAccounts.cacheLock) {
5660 accounts = userAccounts.accountCache.get(accountType);
5661 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005662 if (accounts == null) {
5663 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005664 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005665 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5666 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005667 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005668 } else {
5669 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005670 Account[] accountsArray;
5671 synchronized (userAccounts.cacheLock) {
5672 for (Account[] accounts : userAccounts.accountCache.values()) {
5673 totalLength += accounts.length;
5674 }
5675 if (totalLength == 0) {
5676 return EMPTY_ACCOUNT_ARRAY;
5677 }
5678 accountsArray = new Account[totalLength];
5679 totalLength = 0;
5680 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5681 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5682 accountsOfType.length);
5683 totalLength += accountsOfType.length;
5684 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005685 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005686 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005687 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005688 }
5689 }
5690
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005691 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005692 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005693 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005694 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005695 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005696 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005697 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005698 }
5699 if (value == null) {
5700 userDataForAccount.remove(key);
5701 } else {
5702 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005703 }
5704 }
5705
Carlos Valdivia91979be2015-05-22 14:11:35 -07005706 protected String readCachedTokenInternal(
5707 UserAccounts accounts,
5708 Account account,
5709 String tokenType,
5710 String callingPackage,
5711 byte[] pkgSigDigest) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005712 synchronized (accounts.dbLock) {
5713 synchronized (accounts.cacheLock) {
5714 return accounts.accountTokenCaches.get(
5715 account, tokenType, callingPackage, pkgSigDigest);
5716 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07005717 }
5718 }
5719
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005720 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005721 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005722 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005723 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005724 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005725 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005726 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005727 }
5728 if (value == null) {
5729 authTokensForAccount.remove(key);
5730 } else {
5731 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005732 }
5733 }
5734
Amith Yamasani04e0d262012-02-14 11:50:53 -08005735 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5736 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005737 // Fast path - check if account is already cached
5738 synchronized (accounts.cacheLock) {
5739 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5740 if (authTokensForAccount != null) {
5741 return authTokensForAccount.get(authTokenType);
5742 }
5743 }
5744 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005745 synchronized (accounts.dbLock) {
5746 synchronized (accounts.cacheLock) {
5747 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5748 if (authTokensForAccount == null) {
5749 // need to populate the cache for this account
5750 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
5751 accounts.authTokenCache.put(account, authTokensForAccount);
5752 }
5753 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08005754 }
Fred Quintana56285a62010-12-02 14:20:51 -08005755 }
5756 }
5757
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005758 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
5759 Map<String, String> userDataForAccount;
5760 // Fast path - check if data is already cached
5761 synchronized (accounts.cacheLock) {
5762 userDataForAccount = accounts.userDataCache.get(account);
5763 }
5764 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00005765 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005766 synchronized (accounts.dbLock) {
5767 synchronized (accounts.cacheLock) {
5768 userDataForAccount = accounts.userDataCache.get(account);
5769 if (userDataForAccount == null) {
5770 // need to populate the cache for this account
5771 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
5772 accounts.userDataCache.put(account, userDataForAccount);
5773 }
5774 }
5775 }
Fred Quintana56285a62010-12-02 14:20:51 -08005776 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005777 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005778 }
5779
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005780 private Context getContextForUser(UserHandle user) {
5781 try {
5782 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5783 } catch (NameNotFoundException e) {
5784 // Default to mContext, not finding the package system is running as is unlikely.
5785 return mContext;
5786 }
5787 }
Sandra Kwan78812282015-11-04 11:19:47 -08005788
5789 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5790 try {
5791 response.onResult(result);
5792 } catch (RemoteException e) {
5793 // if the caller is dead then there is no one to care about remote
5794 // exceptions
5795 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5796 Log.v(TAG, "failure while notifying response", e);
5797 }
5798 }
5799 }
5800
5801 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5802 String errorMessage) {
5803 try {
5804 response.onError(errorCode, errorMessage);
5805 } catch (RemoteException e) {
5806 // if the caller is dead then there is no one to care about remote
5807 // exceptions
5808 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5809 Log.v(TAG, "failure while notifying response", e);
5810 }
5811 }
5812 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005813
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005814 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005815 private final Object mLock = new Object();
5816
5817 @GuardedBy("mLock")
5818 private AccountManagerBackupHelper mBackupHelper;
5819
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005820 @Override
5821 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5822 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5823 if (account == null) {
5824 Slog.w(TAG, "account cannot be null");
5825 return;
5826 }
5827 if (packageName == null) {
5828 Slog.w(TAG, "packageName cannot be null");
5829 return;
5830 }
5831 if (userId < UserHandle.USER_SYSTEM) {
5832 Slog.w(TAG, "user id must be concrete");
5833 return;
5834 }
5835 if (callback == null) {
5836 Slog.w(TAG, "callback cannot be null");
5837 return;
5838 }
5839
Svet Ganovf6d424f12016-09-20 20:18:53 -07005840 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5841 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005842 Bundle result = new Bundle();
5843 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5844 callback.sendResult(result);
5845 return;
5846 }
5847
5848 final int uid;
5849 try {
5850 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5851 } catch (NameNotFoundException e) {
5852 Slog.e(TAG, "Unknown package " + packageName);
5853 return;
5854 }
5855
5856 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005857 final UserAccounts userAccounts;
5858 synchronized (mUsers) {
5859 userAccounts = mUsers.get(userId);
5860 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04005861 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005862 doNotification(userAccounts, account, null, intent, packageName, userId);
5863 }
5864
5865 @Override
5866 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5867 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5868 mAppPermissionChangeListeners.add(listener);
5869 }
5870
5871 @Override
5872 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5873 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005874 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005875
5876 @Override
5877 public byte[] backupAccountAccessPermissions(int userId) {
5878 synchronized (mLock) {
5879 if (mBackupHelper == null) {
5880 mBackupHelper = new AccountManagerBackupHelper(
5881 AccountManagerService.this, this);
5882 }
5883 return mBackupHelper.backupAccountAccessPermissions(userId);
5884 }
5885 }
5886
5887 @Override
5888 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5889 synchronized (mLock) {
5890 if (mBackupHelper == null) {
5891 mBackupHelper = new AccountManagerBackupHelper(
5892 AccountManagerService.this, this);
5893 }
5894 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5895 }
5896 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005897 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005898
5899 @VisibleForTesting
5900 static class Injector {
5901 private final Context mContext;
5902
5903 public Injector(Context context) {
5904 mContext = context;
5905 }
5906
5907 Looper getMessageHandlerLooper() {
5908 ServiceThread serviceThread = new ServiceThread(TAG,
5909 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5910 serviceThread.start();
5911 return serviceThread.getLooper();
5912 }
5913
5914 Context getContext() {
5915 return mContext;
5916 }
5917
5918 void addLocalService(AccountManagerInternal service) {
5919 LocalServices.addService(AccountManagerInternal.class, service);
5920 }
5921
5922 String getDeDatabaseName(int userId) {
5923 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5924 AccountsDb.DE_DATABASE_NAME);
5925 return databaseFile.getPath();
5926 }
5927
5928 String getCeDatabaseName(int userId) {
5929 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5930 AccountsDb.CE_DATABASE_NAME);
5931 return databaseFile.getPath();
5932 }
5933
5934 String getPreNDatabaseName(int userId) {
5935 File systemDir = Environment.getDataSystemDirectory();
5936 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5937 PRE_N_DATABASE_NAME);
5938 if (userId == 0) {
5939 // Migrate old file, if it exists, to the new location.
5940 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005941 // accidentally created in the old location,
5942 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005943 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5944 if (oldFile.exists() && !databaseFile.exists()) {
5945 // Check for use directory; create if it doesn't exist, else renameTo will fail
5946 File userDir = Environment.getUserSystemDirectory(userId);
5947 if (!userDir.exists()) {
5948 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005949 throw new IllegalStateException(
5950 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005951 }
5952 }
5953 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005954 throw new IllegalStateException(
5955 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005956 }
5957 }
5958 }
5959 return databaseFile.getPath();
5960 }
5961
5962 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5963 return new AccountAuthenticatorCache(mContext);
5964 }
5965
5966 INotificationManager getNotificationManager() {
5967 return NotificationManager.getService();
5968 }
5969 }
Chris Wren717a8812017-03-31 15:34:39 -04005970
5971 private class NotificationId {
5972 final String mTag;
5973 private final int mId;
5974
5975 NotificationId(String tag, int type) {
5976 mTag = tag;
5977 mId = type;
5978 }
5979 }
Fred Quintana60307342009-03-24 22:48:12 -07005980}