blob: 0ccaf8e914b8c1c7267062b7d63b1845656219c7 [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;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050092import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080093import com.android.internal.util.ArrayUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080094import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -070095import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000096import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -070097import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060098import com.android.server.SystemService;
99
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700100import com.google.android.collect.Lists;
101import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700102
Oscar Montemayora8529f62009-11-18 10:14:20 -0800103import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700104import java.io.FileDescriptor;
105import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800106import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700107import java.security.MessageDigest;
108import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700109import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700110import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800111import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700112import java.util.Collection;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700113import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700114import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700115import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800116import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700117import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800118import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800119import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700120import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700121import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700122import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700123import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700124import java.util.concurrent.atomic.AtomicInteger;
125import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700126
Fred Quintana60307342009-03-24 22:48:12 -0700127/**
128 * A system service that provides account, password, and authtoken management for all
129 * accounts on the device. Some of these calls are implemented with the help of the corresponding
130 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
131 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700132 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700133 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700134 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700135public class AccountManagerService
136 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800137 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700138 private static final String TAG = "AccountManagerService";
139
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600140 public static class Lifecycle extends SystemService {
141 private AccountManagerService mService;
142
143 public Lifecycle(Context context) {
144 super(context);
145 }
146
147 @Override
148 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700149 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600150 publishBinderService(Context.ACCOUNT_SERVICE, mService);
151 }
152
153 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600154 public void onUnlockUser(int userHandle) {
155 mService.onUnlockUser(userHandle);
156 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700157
158 @Override
159 public void onCleanupUser(int userHandle) {
160 mService.onCleanupUser(userHandle);
161 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600162 }
163
Svet Ganov5d09c992016-09-07 09:57:41 -0700164 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700165
Fred Quintana56285a62010-12-02 14:20:51 -0800166 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700167 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700168 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700169 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800170
Svet Ganov5d09c992016-09-07 09:57:41 -0700171 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700172
Fred Quintana60307342009-03-24 22:48:12 -0700173 // Messages that can be sent on mHandler
174 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700175 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700176
Fred Quintana56285a62010-12-02 14:20:51 -0800177 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700178 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700179 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800180
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800181 private static final int SIGNATURE_CHECK_MISMATCH = 0;
182 private static final int SIGNATURE_CHECK_MATCH = 1;
183 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
184
Carlos Valdivia91979be2015-05-22 14:11:35 -0700185 static {
186 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800187 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
188 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700189 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700190
191 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700192 private final AtomicInteger mNotificationIds = new AtomicInteger(1);
193
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;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800197 private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
198 credentialsPermissionNotificationIds =
199 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
200 private final HashMap<Account, Integer> signinRequiredNotificationIds =
201 new HashMap<Account, Integer>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700202 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700203 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800204 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700205 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800206 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700207 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800208 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700209 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700210 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700211 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700212 /** protected by the {@link #cacheLock} */
213 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700214
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700215 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700216 * type -> (packageName -> number of active receivers)
217 * type == null is used to get notifications about all account types
218 */
219 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800220
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700221 /**
222 * protected by the {@link #cacheLock}
223 *
224 * Caches the previous names associated with an account. Previous names
225 * should be cached because we expect that when an Account is renamed,
226 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
227 * want to know if the accounts they care about have been renamed.
228 *
229 * The previous names are wrapped in an {@link AtomicReference} so that
230 * we can distinguish between those accounts with no previous names and
231 * those whose previous names haven't been cached (yet).
232 */
233 private final HashMap<Account, AtomicReference<String>> previousNameCache =
234 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800235
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700236 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700237 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700238
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700239 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800240 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700241 synchronized (dbLock) {
242 synchronized (cacheLock) {
243 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
244 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800245 }
246 }
247 }
248
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700249 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600250 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700251 // Not thread-safe. Only use in synchronized context
252 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700253 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
254 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800255
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700256 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700257 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700258
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700259 /**
260 * This should only be called by system code. One should only call this after the service
261 * has started.
262 * @return a reference to the AccountManagerService instance
263 * @hide
264 */
265 public static AccountManagerService getSingleton() {
266 return sThis.get();
267 }
Fred Quintana60307342009-03-24 22:48:12 -0700268
Fyodor Kupolovda993802016-09-21 14:47:10 -0700269 public AccountManagerService(Injector injector) {
270 mInjector = injector;
271 mContext = injector.getContext();
272 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700273 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700274 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
275 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800276 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700277
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700278 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800279
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800280 IntentFilter intentFilter = new IntentFilter();
281 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
282 intentFilter.addDataScheme("package");
283 mContext.registerReceiver(new BroadcastReceiver() {
284 @Override
285 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700286 // Don't delete accounts when updating a authenticator's
287 // package.
288 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700289 /* Purging data requires file io, don't block the main thread. This is probably
290 * less than ideal because we are introducing a race condition where old grants
291 * could be exercised until they are purged. But that race condition existed
292 * anyway with the broadcast receiver.
293 *
294 * Ideally, we would completely clear the cache, purge data from the database,
295 * and then rebuild the cache. All under the cache lock. But that change is too
296 * large at this point.
297 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800298 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700299 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700300 @Override
301 public void run() {
302 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800303 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800304 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700305 }
306 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700307 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700308 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800309 }
310 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800311
Fyodor Kupolovda993802016-09-21 14:47:10 -0700312 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700313
314 // Need to cancel account request notifications if the update/install can access the account
315 new PackageMonitor() {
316 @Override
317 public void onPackageAdded(String packageName, int uid) {
318 // Called on a handler, and running as the system
319 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
320 }
321
322 @Override
323 public void onPackageUpdateFinished(String packageName, int uid) {
324 // Called on a handler, and running as the system
325 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
326 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700327 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700328
329 // Cancel account request notification if an app op was preventing the account access
330 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
331 new AppOpsManager.OnOpChangedInternalListener() {
332 @Override
333 public void onOpChanged(int op, String packageName) {
334 try {
335 final int userId = ActivityManager.getCurrentUser();
336 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
337 final int mode = mAppOpsManager.checkOpNoThrow(
338 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
339 if (mode == AppOpsManager.MODE_ALLOWED) {
340 final long identity = Binder.clearCallingIdentity();
341 try {
342 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
343 } finally {
344 Binder.restoreCallingIdentity(identity);
345 }
346 }
347 } catch (NameNotFoundException e) {
348 /* ignore */
349 }
350 }
351 });
352
353 // Cancel account request notification if a permission was preventing the account access
354 mPackageManager.addOnPermissionsChangeListener(
355 (int uid) -> {
356 Account[] accounts = null;
357 String[] packageNames = mPackageManager.getPackagesForUid(uid);
358 if (packageNames != null) {
359 final int userId = UserHandle.getUserId(uid);
360 final long identity = Binder.clearCallingIdentity();
361 try {
362 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800363 // if app asked for permission we need to cancel notification even
364 // for O+ applications.
365 if (mPackageManager.checkPermission(
366 Manifest.permission.GET_ACCOUNTS,
367 packageName) != PackageManager.PERMISSION_GRANTED) {
368 continue;
369 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700370
371 if (accounts == null) {
372 accounts = getAccountsAsUser(null, userId, "android");
373 if (ArrayUtils.isEmpty(accounts)) {
374 return;
375 }
376 }
377
378 for (Account account : accounts) {
379 cancelAccountAccessRequestNotificationIfNeeded(
380 account, uid, packageName, true);
381 }
382 }
383 } finally {
384 Binder.restoreCallingIdentity(identity);
385 }
386 }
387 });
388 }
389
390 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
391 boolean checkAccess) {
392 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
393 for (Account account : accounts) {
394 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
395 }
396 }
397
398 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
399 boolean checkAccess) {
400 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
401 for (Account account : accounts) {
402 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
403 }
404 }
405
406 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
407 boolean checkAccess) {
408 String[] packageNames = mPackageManager.getPackagesForUid(uid);
409 if (packageNames != null) {
410 for (String packageName : packageNames) {
411 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
412 packageName, checkAccess);
413 }
414 }
415 }
416
417 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
418 int uid, String packageName, boolean checkAccess) {
419 if (!checkAccess || hasAccountAccess(account, packageName,
420 UserHandle.getUserHandleForUid(uid))) {
421 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700422 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700423 UserHandle.getUserHandleForUid(uid));
424 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800425 }
426
Dianne Hackborn164371f2013-10-01 19:10:13 -0700427 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800428 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800429 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800430 Bundle.setDefusable(extras, true);
431
432 final int callingUid = Binder.getCallingUid();
433 if (Log.isLoggable(TAG, Log.VERBOSE)) {
434 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
435 + ", pid " + Binder.getCallingPid());
436 }
437 Preconditions.checkNotNull(account, "account cannot be null");
438 int userId = UserHandle.getCallingUserId();
439 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
440 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
441 callingUid, account.type);
442 throw new SecurityException(msg);
443 }
444 /*
445 * Child users are not allowed to add accounts. Only the accounts that are shared by the
446 * parent profile can be added to child profile.
447 *
448 * TODO: Only allow accounts that were shared to be added by a limited user.
449 */
450 // fails if the account already exists
451 long identityToken = clearCallingIdentity();
452 try {
453 UserAccounts accounts = getUserAccounts(userId);
454 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800455 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800456 } finally {
457 restoreCallingIdentity(identityToken);
458 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700459 }
460
461 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800462 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
463 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800464 int callingUid = Binder.getCallingUid();
465 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
466 List<String> managedTypes =
467 getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
468
469 if ((accountType != null && !managedTypes.contains(accountType))
470 || (accountType == null && !isSystemUid)) {
471 throw new SecurityException(
472 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
473 + callingUid + " with packageName=" + packageName);
474 }
475 if (accountType != null) {
476 managedTypes = new ArrayList<String>();
477 managedTypes.add(accountType);
478 }
479
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800480 long identityToken = clearCallingIdentity();
481 try {
482 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
483 getUserAccounts(UserHandle.getUserId(callingUid)));
484 } finally {
485 restoreCallingIdentity(identityToken);
486 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800487 }
488
489 /*
490 * accountTypes may not be null
491 */
492 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
493 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
494 int uid = 0;
495 try {
496 uid = mPackageManager.getPackageUidAsUser(packageName,
497 UserHandle.getUserId(callingUid));
498 } catch (NameNotFoundException e) {
499 Log.d(TAG, "Package not found " + e.getMessage());
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800500 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800501 }
502
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800503 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800504 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700505 synchronized (accounts.dbLock) {
506 synchronized (accounts.cacheLock) {
507 final Account[] accountsOfType = accounts.accountCache.get(accountType);
508 if (accountsOfType != null) {
509 for (Account account : accountsOfType) {
510 result.put(account,
511 resolveAccountVisibility(account, packageName, accounts));
512 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800513 }
514 }
515 }
516 }
517 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800518 }
519
520 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800521 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700522 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700523 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800524 int userId = UserHandle.getUserId(callingUid);
525 UserAccounts accounts = getUserAccounts(userId);
526 if (!isAccountManagedByCaller(account.type, callingUid, userId)
527 && !isSystemUid(callingUid)) {
528 String msg =
529 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700530 throw new SecurityException(msg);
531 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700532 synchronized (accounts.dbLock) {
533 synchronized (accounts.cacheLock) {
534 return getPackagesAndVisibilityForAccountLocked(account, accounts);
535 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700536 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800537 }
538
539 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700540 * Returns Map with all package names and visibility values for given account.
541 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800542 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800543 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800544 * @param accounts UserAccount that currently hosts the account and application
545 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700546 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800547 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700548 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800549 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700550 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
551 if (accountVisibility == null) {
552 Log.d(TAG, "Visibility was not initialized");
553 accountVisibility = new HashMap<>();
554 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800555 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700556 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700557 }
558
559 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700560 public int getAccountVisibility(Account account, String packageName) {
561 Preconditions.checkNotNull(account, "account cannot be null");
562 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800563 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700564 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
565 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800566 && !isSystemUid(callingUid)) {
567 String msg = String.format(
568 "uid %s cannot get secrets for accounts of type: %s",
569 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700570 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800571 throw new SecurityException(msg);
572 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700573 return resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800574 }
575
576 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800577 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800578 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800579 * @param account The account to check visibility.
580 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800581 * @param accounts UserAccount that currently hosts the account and application
582 *
583 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
584 *
585 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700586 private int getAccountVisibilityFromCache(Account account, String packageName,
587 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700588 synchronized (accounts.cacheLock) {
589 Map<String, Integer> accountVisibility =
590 getPackagesAndVisibilityForAccountLocked(account, accounts);
591 Integer visibility = accountVisibility.get(packageName);
592 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800593 }
594 }
595
596 /**
597 * Method which handles default values for Account visibility.
598 *
599 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800600 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800601 * @param accounts UserAccount that currently hosts the account and application
602 *
603 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
604 *
605 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800606 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800607 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800608 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800609 int uid = -1;
610 try {
611 long identityToken = clearCallingIdentity();
612 try {
613 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
614 } finally {
615 restoreCallingIdentity(identityToken);
616 }
617 } catch (NameNotFoundException e) {
618 Log.d(TAG, "Package not found " + e.getMessage());
619 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800620 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800621
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800622 // System visibility can not be restricted.
623 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
624 return AccountManager.VISIBILITY_VISIBLE;
625 }
626
627 int signatureCheckResult =
628 checkPackageSignature(account.type, uid, accounts.userId);
629
630 // Authenticator can not restrict visibility to itself.
631 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
632 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
633 }
634
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800635 if (isSpecialPackageKey(packageName)) {
636 Log.d(TAG, "Package name is forbidden: " + packageName);
637 return AccountManager.VISIBILITY_NOT_VISIBLE;
638 }
639
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800640 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700641 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800642
643 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
644 return visibility;
645 }
646
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800647 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
648 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
649
650 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800651 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800652 return AccountManager.VISIBILITY_VISIBLE;
653 }
654 // Apps with READ_CONTACTS permission get visibility by default even post O.
655 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
656
657 boolean preO = isPreOApplication(packageName);
658 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
659 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800660 || canReadContacts || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800661 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
662 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700663 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800664 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800665 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
666 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
667 }
668 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700669 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800670 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800671 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
672 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
673 }
674 }
675 return visibility;
676 }
677
678 /**
679 * Checks targetSdk for a package;
680 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800681 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800682 *
683 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
684 * undefined
685 */
686 private boolean isPreOApplication(String packageName) {
687 try {
688 long identityToken = clearCallingIdentity();
689 ApplicationInfo applicationInfo;
690 try {
691 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
692 } finally {
693 restoreCallingIdentity(identityToken);
694 }
695
696 if (applicationInfo != null) {
697 int version = applicationInfo.targetSdkVersion;
698 return version < android.os.Build.VERSION_CODES.O;
699 }
700 return true;
701 } catch (NameNotFoundException e) {
702 Log.d(TAG, "Package not found " + e.getMessage());
703 return true;
704 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800705 }
706
707 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700708 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
709 Preconditions.checkNotNull(account, "account cannot be null");
710 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800711 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700712 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
713 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800714 && !isSystemUid(callingUid)) {
715 String msg = String.format(
716 "uid %s cannot get secrets for accounts of type: %s",
717 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700718 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800719 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700720 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700721 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
722 accounts);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700723 }
724
725 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800726 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700727 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800728 * @param account Account to update visibility.
729 * @param packageName Package name for which visibility is updated.
730 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800731 * @param notify if the flag is set applications will get notification about visibility change
732 * @param accounts UserAccount that currently hosts the account and application
733 *
734 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700735 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800736 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800737 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700738 synchronized (accounts.dbLock) {
739 synchronized (accounts.cacheLock) {
740 Map<String, Integer> packagesToVisibility;
741 if (notify) {
742 if (isSpecialPackageKey(packageName)) {
743 packagesToVisibility =
744 getRequestingPackages(account, accounts);
745 } else {
746 if (!packageExistsForUser(packageName, accounts.userId)) {
747 return false; // package is not installed.
748 }
749 packagesToVisibility = new HashMap<>();
750 packagesToVisibility.put(packageName,
751 resolveAccountVisibility(account, packageName, accounts));
752 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800753 } else {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700754 // Notifications will not be send.
755 if (!isSpecialPackageKey(packageName) &&
756 !packageExistsForUser(packageName, accounts.userId)) {
757 // package is not installed and not meta value.
758 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100759 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700760 packagesToVisibility = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800761 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700762
763 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800764 return false;
765 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800766
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700767 if (notify) {
768 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
769 .entrySet()) {
770 if (packageToVisibility.getValue()
771 != AccountManager.VISIBILITY_NOT_VISIBLE) {
772 notifyPackage(packageToVisibility.getKey(), accounts);
773 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700774 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700775 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700776 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700777 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800778 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700779 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700780 }
781
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700782 // Update account visibility in cache and database.
783 private boolean updateAccountVisibilityLocked(Account account, String packageName,
784 int newVisibility, UserAccounts accounts) {
785 final long accountId = accounts.accountsDb.findDeAccountId(account);
786 if (accountId < 0) {
787 return false;
788 }
789
790 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
791 try {
792 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
793 newVisibility)) {
794 return false;
795 }
796 } finally {
797 StrictMode.setThreadPolicy(oldPolicy);
798 }
799 Map<String, Integer> accountVisibility =
800 getPackagesAndVisibilityForAccountLocked(account, accounts);
801 accountVisibility.put(packageName, newVisibility);
802 return true;
803 }
804
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700805 @Override
806 public void registerAccountListener(String[] accountTypes, String opPackageName) {
807 int callingUid = Binder.getCallingUid();
808 mAppOpsManager.checkPackage(callingUid, opPackageName);
809 registerAccountListener(accountTypes, opPackageName,
810 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800811 }
812
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700813 private void registerAccountListener(String[] accountTypes, String opPackageName,
814 UserAccounts accounts) {
815 synchronized (accounts.mReceiversForType) {
816 if (accountTypes == null) {
817 // null for any type
818 accountTypes = new String[] {null};
819 }
820 for (String type : accountTypes) {
821 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
822 if (receivers == null) {
823 receivers = new HashMap<>();
824 accounts.mReceiversForType.put(type, receivers);
825 }
826 Integer cnt = receivers.get(opPackageName);
827 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800828 }
829 }
830 }
831
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700832 @Override
833 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
834 int callingUid = Binder.getCallingUid();
835 mAppOpsManager.checkPackage(callingUid, opPackageName);
836 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
837 synchronized (accounts.mReceiversForType) {
838 if (accountTypes == null) {
839 // null for any type
840 accountTypes = new String[] {null};
841 }
842 for (String type : accountTypes) {
843 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
844 if (receivers == null || receivers.get(opPackageName) == null) {
845 throw new IllegalArgumentException("attempt to unregister wrong receiver");
846 }
847 Integer cnt = receivers.get(opPackageName);
848 if (cnt == 1) {
849 receivers.remove(opPackageName);
850 } else {
851 receivers.put(opPackageName, cnt - 1);
852 }
853 }
854 }
855 }
856
857 // Send notification to all packages which can potentially see the account
858 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
859 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
860 // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
861 // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
862 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
863 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
864 notifyPackage(packageToVisibility.getKey(), accounts);
865 }
866 }
867 }
868
869 /**
870 * Sends a direct intent to a package, notifying it of account visibility change.
871 *
872 * @param packageName to send Account to
873 * @param accounts UserAccount that currently hosts the account
874 */
875 private void notifyPackage(String packageName, UserAccounts accounts) {
876 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
877 intent.setPackage(packageName);
878 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
879 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
880 }
881
882 // Returns a map from package name to visibility, for packages subscribed
883 // to notifications about any account type, or type of provided account
884 // account type or all types.
885 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
886 Set<String> packages = new HashSet<>();
887 synchronized (accounts.mReceiversForType) {
888 for (String type : new String[] {account.type, null}) {
889 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
890 if (receivers != null) {
891 packages.addAll(receivers.keySet());
892 }
893 }
894 }
895 Map<String, Integer> result = new HashMap<>();
896 for (String packageName : packages) {
897 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
898 }
899 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800900 }
901
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800902 private boolean packageExistsForUser(String packageName, int userId) {
903 try {
904 long identityToken = clearCallingIdentity();
905 try {
906 mPackageManager.getPackageUidAsUser(packageName, userId);
907 return true; // package exist
908 } finally {
909 restoreCallingIdentity(identityToken);
910 }
911 } catch (NameNotFoundException e) {
912 return false;
913 }
914 }
915
916 /**
917 * Returns true if packageName is one of special values.
918 */
919 private boolean isSpecialPackageKey(String packageName) {
920 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
921 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
922 }
923
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800924 private void sendAccountsChangedBroadcast(int userId) {
925 Log.i(TAG, "the accounts changed, sending broadcast of "
926 + ACCOUNTS_CHANGED_INTENT.getAction());
927 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700928 }
929
930 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700931 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
932 throws RemoteException {
933 try {
934 return super.onTransact(code, data, reply, flags);
935 } catch (RuntimeException e) {
936 // The account manager only throws security exceptions, so let's
937 // log all others.
938 if (!(e instanceof SecurityException)) {
939 Slog.wtf(TAG, "Account Manager Crash", e);
940 }
941 throw e;
942 }
943 }
944
Amith Yamasani258848d2012-08-10 17:06:33 -0700945 private UserManager getUserManager() {
946 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700947 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700948 }
949 return mUserManager;
950 }
951
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700952 /**
953 * Validate internal set of accounts against installed authenticators for
954 * given user. Clears cached authenticators before validating.
955 */
956 public void validateAccounts(int userId) {
957 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700958 // Invalidate user-specific cache to make sure we catch any
959 // removed authenticators.
960 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
961 }
962
963 /**
964 * Validate internal set of accounts against installed authenticators for
965 * given user. Clear cached authenticators before validating when requested.
966 */
967 private void validateAccountsInternal(
968 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700969 if (Log.isLoggable(TAG, Log.DEBUG)) {
970 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700971 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600972 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700973 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700974
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700975 if (invalidateAuthenticatorCache) {
976 mAuthenticatorCache.invalidateCache(accounts.userId);
977 }
978
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700979 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
980 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700981 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700982
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700983 synchronized (accounts.dbLock) {
984 synchronized (accounts.cacheLock) {
985 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800986
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700987 // Get a map of stored authenticator types to UID
988 final AccountsDb accountsDb = accounts.accountsDb;
989 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
990 // Create a list of authenticator type whose previous uid no longer exists
991 HashSet<String> obsoleteAuthType = Sets.newHashSet();
992 SparseBooleanArray knownUids = null;
993 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
994 String type = authToUidEntry.getKey();
995 int uid = authToUidEntry.getValue();
996 Integer knownUid = knownAuth.get(type);
997 if (knownUid != null && uid == knownUid) {
998 // Remove it from the knownAuth list if it's unchanged.
999 knownAuth.remove(type);
1000 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001001 /*
1002 * The authenticator is presently not cached and should only be triggered
1003 * when we think an authenticator has been removed (or is being updated).
1004 * But we still want to check if any data with the associated uid is
1005 * around. This is an (imperfect) signal that the package may be updating.
1006 *
1007 * A side effect of this is that an authenticator sharing a uid with
1008 * multiple apps won't get its credentials wiped as long as some app with
1009 * that uid is still on the device. But I suspect that this is a rare case.
1010 * And it isn't clear to me how an attacker could really exploit that
1011 * feature.
1012 *
1013 * The upshot is that we don't have to worry about accounts getting
1014 * uninstalled while the authenticator's package is being updated.
1015 *
1016 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001017 if (knownUids == null) {
1018 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1019 }
1020 if (!knownUids.get(uid)) {
1021 // The authenticator is not presently available to the cache. And the
1022 // package no longer has a data directory (so we surmise it isn't
1023 // updating). So purge its data from the account databases.
1024 obsoleteAuthType.add(type);
1025 // And delete it from the TABLE_META
1026 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1027 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001028 }
1029 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001030
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001031 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1032 // been re-enabled (after being updated for example), then we just overwrite the old
1033 // values.
1034 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1035 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1036 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001037
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001038 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1039 try {
1040 accounts.accountCache.clear();
1041 final HashMap<String, ArrayList<String>> accountNamesByType
1042 = new LinkedHashMap<>();
1043 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1044 final long accountId = accountEntry.getKey();
1045 final Account account = accountEntry.getValue();
1046 if (obsoleteAuthType.contains(account.type)) {
1047 Slog.w(TAG, "deleting account " + account.name + " because type "
1048 + account.type
1049 + "'s registered authenticator no longer exist.");
1050 Map<String, Integer> packagesToVisibility =
1051 getRequestingPackages(account, accounts);
1052 accountsDb.beginTransaction();
1053 try {
1054 accountsDb.deleteDeAccount(accountId);
1055 // Also delete from CE table if user is unlocked; if user is
1056 // currently locked the account will be removed later by
1057 // syncDeCeAccountsLocked
1058 if (userUnlocked) {
1059 accountsDb.deleteCeAccount(accountId);
1060 }
1061 accountsDb.setTransactionSuccessful();
1062 } finally {
1063 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001064 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001065 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001066
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001067 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1068 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001069
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001070 accounts.userDataCache.remove(account);
1071 accounts.authTokenCache.remove(account);
1072 accounts.accountTokenCaches.remove(account);
1073 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001074
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001075 for (Entry<String, Integer> packageToVisibility :
1076 packagesToVisibility.entrySet()) {
1077 if (packageToVisibility.getValue()
1078 != AccountManager.VISIBILITY_NOT_VISIBLE) {
1079 notifyPackage(packageToVisibility.getKey(), accounts);
1080 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001081 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001082 } else {
1083 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1084 if (accountNames == null) {
1085 accountNames = new ArrayList<>();
1086 accountNamesByType.put(account.type, accountNames);
1087 }
1088 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001089 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001090 }
1091 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1092 final String accountType = cur.getKey();
1093 final ArrayList<String> accountNames = cur.getValue();
1094 final Account[] accountsForType = new Account[accountNames.size()];
1095 for (int i = 0; i < accountsForType.length; i++) {
1096 accountsForType[i] = new Account(accountNames.get(i), accountType,
1097 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001098 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001099 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001100 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001101 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1102 } finally {
1103 if (accountDeleted) {
1104 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001105 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001106 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001107 }
1108 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001109 }
1110
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001111 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1112 // Get the UIDs of all apps that might have data on the device. We want
1113 // to preserve user data if the app might otherwise be storing data.
1114 List<PackageInfo> pkgsWithData =
1115 mPackageManager.getInstalledPackagesAsUser(
1116 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1117 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1118 for (PackageInfo pkgInfo : pkgsWithData) {
1119 if (pkgInfo.applicationInfo != null
1120 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1121 knownUids.put(pkgInfo.applicationInfo.uid, true);
1122 }
1123 }
1124 return knownUids;
1125 }
1126
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001127 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001128 Context context,
1129 int userId) {
1130 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001131 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1132 }
1133
1134 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1135 IAccountAuthenticatorCache authCache,
1136 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001137 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001138 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1139 .getAllServices(userId)) {
1140 knownAuth.put(service.type.type, service.uid);
1141 }
1142 return knownAuth;
1143 }
1144
Amith Yamasani04e0d262012-02-14 11:50:53 -08001145 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001146 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001147 }
1148
1149 protected UserAccounts getUserAccounts(int userId) {
1150 synchronized (mUsers) {
1151 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001152 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001153 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001154 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1155 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001156 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001157 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001158 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001159 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001160 validateAccounts = true;
1161 }
1162 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001163 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001164 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001165 synchronized (accounts.dbLock) {
1166 synchronized (accounts.cacheLock) {
1167 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1168 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1169 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001170 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001171 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001172 }
1173 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001174 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001175 }
1176 return accounts;
1177 }
1178 }
1179
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001180 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1181 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001182 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001183 if (!accountsToRemove.isEmpty()) {
1184 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1185 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001186 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1187 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001188
1189 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001190 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001191 }
1192 }
1193 }
1194
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001195 private void purgeOldGrantsAll() {
1196 synchronized (mUsers) {
1197 for (int i = 0; i < mUsers.size(); i++) {
1198 purgeOldGrants(mUsers.valueAt(i));
1199 }
1200 }
1201 }
1202
1203 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001204 synchronized (accounts.dbLock) {
1205 synchronized (accounts.cacheLock) {
1206 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1207 for (int uid : uids) {
1208 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1209 if (packageExists) {
1210 continue;
1211 }
1212 Log.d(TAG, "deleting grants for UID " + uid
1213 + " because its package is no longer installed");
1214 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001215 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001216 }
1217 }
1218 }
1219
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001220 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001221 if (isSpecialPackageKey(packageName)) {
1222 return;
1223 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001224 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001225 int numberOfUsers = mUsers.size();
1226 for (int i = 0; i < numberOfUsers; i++) {
1227 UserAccounts accounts = mUsers.valueAt(i);
1228 try {
1229 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1230 } catch (NameNotFoundException e) {
1231 // package does not exist - remove visibility values
1232 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001233 synchronized (accounts.dbLock) {
1234 synchronized (accounts.cacheLock) {
1235 for (Account account : accounts.visibilityCache.keySet()) {
1236 Map<String, Integer> accountVisibility =
1237 getPackagesAndVisibilityForAccountLocked(account, accounts);
1238 accountVisibility.remove(packageName);
1239 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001240 }
1241 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001242 }
1243 }
1244 }
1245 }
1246
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001247
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -07001248 private void onCleanupUser(int userId) {
1249 Log.i(TAG, "onCleanupUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001250 UserAccounts accounts;
1251 synchronized (mUsers) {
1252 accounts = mUsers.get(userId);
1253 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001254 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001255 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001256 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001257 synchronized (accounts.dbLock) {
1258 synchronized (accounts.cacheLock) {
1259 accounts.accountsDb.close();
1260 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001261 }
Amith Yamasani13593602012-03-22 16:16:17 -07001262 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001263 }
1264
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001265 @VisibleForTesting
1266 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001267 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1268 }
1269
1270 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001271 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1272 Log.v(TAG, "onUserUnlocked " + userId);
1273 }
1274 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001275 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001276 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001277 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001278 syncSharedAccounts(userId);
1279 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001280
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001281 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001282 // Check if there's a shared account that needs to be created as an account
1283 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1284 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001285 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001286 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001287 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001288 : UserHandle.USER_SYSTEM;
1289 if (parentUserId < 0) {
1290 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1291 return;
1292 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001293 for (Account sa : sharedAccounts) {
1294 if (ArrayUtils.contains(accounts, sa)) continue;
1295 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001296 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001297 }
1298 }
1299
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001300 @Override
1301 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001302 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001303 }
1304
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001305 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001306 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001307 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001308 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1309 Log.v(TAG, "getPassword: " + account
1310 + ", caller's uid " + Binder.getCallingUid()
1311 + ", pid " + Binder.getCallingPid());
1312 }
Fred Quintana382601f2010-03-25 12:25:10 -07001313 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001314 int userId = UserHandle.getCallingUserId();
1315 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001316 String msg = String.format(
1317 "uid %s cannot get secrets for accounts of type: %s",
1318 callingUid,
1319 account.type);
1320 throw new SecurityException(msg);
1321 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001322 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001323 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001324 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001325 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001326 } finally {
1327 restoreCallingIdentity(identityToken);
1328 }
1329 }
1330
Amith Yamasani04e0d262012-02-14 11:50:53 -08001331 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001332 if (account == null) {
1333 return null;
1334 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001335 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001336 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1337 return null;
1338 }
Fred Quintana31957f12009-10-21 13:43:10 -07001339
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001340 synchronized (accounts.dbLock) {
1341 synchronized (accounts.cacheLock) {
1342 return accounts.accountsDb
1343 .findAccountPasswordByNameAndType(account.name, account.type);
1344 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001345 }
1346 }
1347
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001348 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001349 public String getPreviousName(Account account) {
1350 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1351 Log.v(TAG, "getPreviousName: " + account
1352 + ", caller's uid " + Binder.getCallingUid()
1353 + ", pid " + Binder.getCallingPid());
1354 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001355 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001356 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001357 long identityToken = clearCallingIdentity();
1358 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001359 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001360 return readPreviousNameInternal(accounts, account);
1361 } finally {
1362 restoreCallingIdentity(identityToken);
1363 }
1364 }
1365
1366 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1367 if (account == null) {
1368 return null;
1369 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001370 synchronized (accounts.dbLock) {
1371 synchronized (accounts.cacheLock) {
1372 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1373 if (previousNameRef == null) {
1374 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1375 previousNameRef = new AtomicReference<>(previousName);
1376 accounts.previousNameCache.put(account, previousNameRef);
1377 return previousName;
1378 } else {
1379 return previousNameRef.get();
1380 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001381 }
1382 }
1383 }
1384
1385 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001386 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001387 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001388 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001389 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1390 account, key, callingUid, Binder.getCallingPid());
1391 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001392 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001393 Preconditions.checkNotNull(account, "account cannot be null");
1394 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001395 int userId = UserHandle.getCallingUserId();
1396 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001397 String msg = String.format(
1398 "uid %s cannot get user data for accounts of type: %s",
1399 callingUid,
1400 account.type);
1401 throw new SecurityException(msg);
1402 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001403 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001404 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1405 return null;
1406 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001407 long identityToken = clearCallingIdentity();
1408 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001409 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001410 synchronized (accounts.dbLock) {
1411 synchronized (accounts.cacheLock) {
1412 if (!accountExistsCacheLocked(accounts, account)) {
1413 return null;
1414 }
1415 return readUserDataInternalLocked(accounts, account, key);
Simranjit Kohli858511c2016-03-10 18:36:11 +00001416 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00001417 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001418 } finally {
1419 restoreCallingIdentity(identityToken);
1420 }
1421 }
1422
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001423 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001424 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001425 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001426 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1427 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001428 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001429 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001430 + ", pid " + Binder.getCallingPid());
1431 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001432 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001433 if (isCrossUser(callingUid, userId)) {
1434 throw new SecurityException(
1435 String.format(
1436 "User %s tying to get authenticator types for %s" ,
1437 UserHandle.getCallingUserId(),
1438 userId));
1439 }
1440
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001441 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001442 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001443 return getAuthenticatorTypesInternal(userId);
1444
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001445 } finally {
1446 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001447 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001448 }
1449
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001450 /**
1451 * Should only be called inside of a clearCallingIdentity block.
1452 */
1453 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001454 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001455 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1456 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1457 AuthenticatorDescription[] types =
1458 new AuthenticatorDescription[authenticatorCollection.size()];
1459 int i = 0;
1460 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1461 : authenticatorCollection) {
1462 types[i] = authenticator.type;
1463 i++;
1464 }
1465 return types;
1466 }
1467
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001468 private boolean isCrossUser(int callingUid, int userId) {
1469 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001470 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001471 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001472 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1473 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001474 }
1475
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001476 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001477 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001478 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001479 }
1480
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001481 @Override
1482 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001483 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001484 int callingUid = Binder.getCallingUid();
1485 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1486 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001487 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001488 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001489 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1490 final UserAccounts toAccounts = getUserAccounts(userTo);
1491 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001492 if (response != null) {
1493 Bundle result = new Bundle();
1494 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1495 try {
1496 response.onResult(result);
1497 } catch (RemoteException e) {
1498 Slog.w(TAG, "Failed to report error back to the client." + e);
1499 }
1500 }
1501 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001502 }
1503
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001504 Slog.d(TAG, "Copying account " + account.name
1505 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001506 long identityToken = clearCallingIdentity();
1507 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001508 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001509 false /* stripAuthTokenFromResult */, account.name,
1510 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001511 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001512 protected String toDebugString(long now) {
1513 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1514 + ", " + account.type;
1515 }
1516
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001517 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001518 public void run() throws RemoteException {
1519 mAuthenticator.getAccountCredentialsForCloning(this, account);
1520 }
1521
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001522 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001523 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001524 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001525 if (result != null
1526 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1527 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001528 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001529 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001530 super.onResult(result);
1531 }
1532 }
1533 }.bind();
1534 } finally {
1535 restoreCallingIdentity(identityToken);
1536 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001537 }
1538
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001539 @Override
1540 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001541 final int callingUid = Binder.getCallingUid();
1542 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1543 String msg = String.format(
1544 "accountAuthenticated( account: %s, callerUid: %s)",
1545 account,
1546 callingUid);
1547 Log.v(TAG, msg);
1548 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001549 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001550 int userId = UserHandle.getCallingUserId();
1551 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001552 String msg = String.format(
1553 "uid %s cannot notify authentication for accounts of type: %s",
1554 callingUid,
1555 account.type);
1556 throw new SecurityException(msg);
1557 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001558
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001559 if (!canUserModifyAccounts(userId, callingUid) ||
1560 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001561 return false;
1562 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001563
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001564 long identityToken = clearCallingIdentity();
1565 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001566 UserAccounts accounts = getUserAccounts(userId);
1567 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001568 } finally {
1569 restoreCallingIdentity(identityToken);
1570 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001571 }
1572
1573 private boolean updateLastAuthenticatedTime(Account account) {
1574 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001575 synchronized (accounts.dbLock) {
1576 synchronized (accounts.cacheLock) {
1577 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1578 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001579 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001580 }
1581
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001582 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001583 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1584 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001585 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001586 long id = clearCallingIdentity();
1587 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001588 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001589 false /* stripAuthTokenFromResult */, account.name,
1590 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001591 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001592 protected String toDebugString(long now) {
1593 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1594 + ", " + account.type;
1595 }
1596
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001597 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001598 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001599 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001600 UserAccounts owner = getUserAccounts(parentUserId);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001601 synchronized (owner.dbLock) {
1602 synchronized (owner.cacheLock) {
1603 for (Account acc : getAccounts(parentUserId,
1604 mContext.getOpPackageName())) {
1605 if (acc.equals(account)) {
1606 mAuthenticator.addAccountFromCredentials(
1607 this, account, accountCredentials);
1608 break;
1609 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001610 }
1611 }
1612 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001613 }
1614
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001615 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001616 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001617 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001618 // TODO: Anything to do if if succedded?
1619 // TODO: If it failed: Show error notification? Should we remove the shadow
1620 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001621 // TODO: what we do with the visibility?
1622
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001623 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001624 }
1625
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001626 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001627 public void onError(int errorCode, String errorMessage) {
1628 super.onError(errorCode, errorMessage);
1629 // TODO: Show error notification to user
1630 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1631 }
1632
1633 }.bind();
1634 } finally {
1635 restoreCallingIdentity(id);
1636 }
1637 }
1638
Amith Yamasani04e0d262012-02-14 11:50:53 -08001639 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001640 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001641 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001642 if (account == null) {
1643 return false;
1644 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001645 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001646 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1647 + " is locked. callingUid=" + callingUid);
1648 return false;
1649 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001650 synchronized (accounts.dbLock) {
1651 synchronized (accounts.cacheLock) {
1652 accounts.accountsDb.beginTransaction();
1653 try {
1654 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1655 Log.w(TAG, "insertAccountIntoDatabase: " + account
1656 + ", skipping since the account already exists");
1657 return false;
1658 }
1659 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1660 if (accountId < 0) {
1661 Log.w(TAG, "insertAccountIntoDatabase: " + account
1662 + ", skipping the DB insert failed");
1663 return false;
1664 }
1665 // Insert into DE table
1666 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1667 Log.w(TAG, "insertAccountIntoDatabase: " + account
1668 + ", skipping the DB insert failed");
1669 return false;
1670 }
1671 if (extras != null) {
1672 for (String key : extras.keySet()) {
1673 final String value = extras.getString(key);
1674 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1675 Log.w(TAG, "insertAccountIntoDatabase: " + account
1676 + ", skipping since insertExtra failed for key " + key);
1677 return false;
1678 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001679 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001680 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001681
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001682 if (packageToVisibility != null) {
1683 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1684 setAccountVisibility(account, entry.getKey() /* package */,
1685 entry.getValue() /* visibility */, false /* notify */,
1686 accounts);
1687 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001688 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001689 accounts.accountsDb.setTransactionSuccessful();
1690
1691 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1692 accountId,
1693 accounts, callingUid);
1694
1695 insertAccountIntoCacheLocked(accounts, account);
1696 } finally {
1697 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001698 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001699 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001700 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001701 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1702 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001703 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001704
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001705 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001706 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1707 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001708
Amith Yamasani5be347b2013-03-31 17:44:31 -07001709 return true;
1710 }
1711
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001712 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001713 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001714 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001715 }
1716 }
1717
Amith Yamasani5be347b2013-03-31 17:44:31 -07001718 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001719 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001720 * running, then clone the account too.
1721 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001722 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001723 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001724 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001725 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001726 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001727 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001728 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001729 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001730 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001731 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001732 }
1733 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001734 }
1735 }
1736
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001737 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001738 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001739 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001740 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001741 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001742 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1743 Log.v(TAG, "hasFeatures: " + account
1744 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001745 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001746 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001747 + ", pid " + Binder.getCallingPid());
1748 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001749 Preconditions.checkArgument(account != null, "account cannot be null");
1750 Preconditions.checkArgument(response != null, "response cannot be null");
1751 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001752 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001753 checkReadAccountsPermitted(callingUid, account.type, userId,
1754 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001755
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001756 long identityToken = clearCallingIdentity();
1757 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001758 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001759 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001760 } finally {
1761 restoreCallingIdentity(identityToken);
1762 }
1763 }
1764
1765 private class TestFeaturesSession extends Session {
1766 private final String[] mFeatures;
1767 private final Account mAccount;
1768
Amith Yamasani04e0d262012-02-14 11:50:53 -08001769 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001770 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001771 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001772 true /* stripAuthTokenFromResult */, account.name,
1773 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001774 mFeatures = features;
1775 mAccount = account;
1776 }
1777
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001778 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001779 public void run() throws RemoteException {
1780 try {
1781 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1782 } catch (RemoteException e) {
1783 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1784 }
1785 }
1786
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001787 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001788 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001789 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001790 IAccountManagerResponse response = getResponseAndClose();
1791 if (response != null) {
1792 try {
1793 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001794 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001795 return;
1796 }
Fred Quintana56285a62010-12-02 14:20:51 -08001797 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1798 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1799 + response);
1800 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001801 final Bundle newResult = new Bundle();
1802 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1803 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1804 response.onResult(newResult);
1805 } catch (RemoteException e) {
1806 // if the caller is dead then there is no one to care about remote exceptions
1807 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1808 Log.v(TAG, "failure while notifying response", e);
1809 }
1810 }
1811 }
1812 }
1813
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001814 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001815 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001816 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001817 + ", " + mAccount
1818 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1819 }
1820 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001821
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001822 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001823 public void renameAccount(
1824 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001825 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001826 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1827 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001828 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001829 + ", pid " + Binder.getCallingPid());
1830 }
1831 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001832 int userId = UserHandle.getCallingUserId();
1833 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001834 String msg = String.format(
1835 "uid %s cannot rename accounts of type: %s",
1836 callingUid,
1837 accountToRename.type);
1838 throw new SecurityException(msg);
1839 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001840 long identityToken = clearCallingIdentity();
1841 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001842 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001843 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001844 Bundle result = new Bundle();
1845 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1846 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001847 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1848 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001849 try {
1850 response.onResult(result);
1851 } catch (RemoteException e) {
1852 Log.w(TAG, e.getMessage());
1853 }
1854 } finally {
1855 restoreCallingIdentity(identityToken);
1856 }
1857 }
1858
1859 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001860 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001861 Account resultAccount = null;
1862 /*
1863 * Cancel existing notifications. Let authenticators
1864 * re-post notifications as required. But we don't know if
1865 * the authenticators have bound their notifications to
1866 * now stale account name data.
1867 *
1868 * With a rename api, we might not need to do this anymore but it
1869 * shouldn't hurt.
1870 */
1871 cancelNotification(
1872 getSigninRequiredNotificationId(accounts, accountToRename),
1873 new UserHandle(accounts.userId));
1874 synchronized(accounts.credentialsPermissionNotificationIds) {
1875 for (Pair<Pair<Account, String>, Integer> pair:
1876 accounts.credentialsPermissionNotificationIds.keySet()) {
1877 if (accountToRename.equals(pair.first.first)) {
1878 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1879 cancelNotification(id, new UserHandle(accounts.userId));
1880 }
1881 }
1882 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001883 synchronized (accounts.dbLock) {
1884 synchronized (accounts.cacheLock) {
1885 accounts.accountsDb.beginTransaction();
1886 Account renamedAccount = new Account(newName, accountToRename.type);
1887 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1888 Log.e(TAG, "renameAccount failed - account with new name already exists");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001889 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001890 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001891 try {
1892 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
1893 if (accountId >= 0) {
1894 accounts.accountsDb.renameCeAccount(accountId, newName);
1895 if (accounts.accountsDb.renameDeAccount(
1896 accountId, newName, accountToRename.name)) {
1897 accounts.accountsDb.setTransactionSuccessful();
1898 } else {
1899 Log.e(TAG, "renameAccount failed");
1900 return null;
1901 }
1902 } else {
1903 Log.e(TAG, "renameAccount failed - old account does not exist");
1904 return null;
1905 }
1906 } finally {
1907 accounts.accountsDb.endTransaction();
1908 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001909 /*
1910 * Database transaction was successful. Clean up cached
1911 * data associated with the account in the user profile.
1912 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001913 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001914 /*
1915 * Extract the data and token caches before removing the
1916 * old account to preserve the user data associated with
1917 * the account.
1918 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001919 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1920 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
1921 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
1922 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001923 /*
1924 * Update the cached data associated with the renamed
1925 * account.
1926 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001927 accounts.userDataCache.put(renamedAccount, tmpData);
1928 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1929 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
1930 accounts.previousNameCache.put(
1931 renamedAccount,
1932 new AtomicReference<>(accountToRename.name));
1933 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001934
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001935 int parentUserId = accounts.userId;
1936 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001937 /*
1938 * Owner or system user account was renamed, rename the account for
1939 * those users with which the account was shared.
1940 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001941 List<UserInfo> users = getUserManager().getUsers(true);
1942 for (UserInfo user : users) {
1943 if (user.isRestricted()
1944 && (user.restrictedProfileParentId == parentUserId)) {
1945 renameSharedAccountAsUser(accountToRename, newName, user.id);
1946 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001947 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001948 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001949
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001950 sendNotificationAccountUpdated(resultAccount, accounts);
1951 sendAccountsChangedBroadcast(accounts.userId);
1952 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001953 }
1954 return resultAccount;
1955 }
1956
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001957 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001958 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001959 return userInfo != null && userInfo.canHaveProfile();
1960 }
1961
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001962 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001963 public void removeAccount(IAccountManagerResponse response, Account account,
1964 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001965 removeAccountAsUser(
1966 response,
1967 account,
1968 expectActivityLaunch,
1969 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001970 }
1971
1972 @Override
1973 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001974 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001975 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001976 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1977 Log.v(TAG, "removeAccount: " + account
1978 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001979 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001980 + ", pid " + Binder.getCallingPid()
1981 + ", for user id " + userId);
1982 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001983 Preconditions.checkArgument(account != null, "account cannot be null");
1984 Preconditions.checkArgument(response != null, "response cannot be null");
1985
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001986 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001987 if (isCrossUser(callingUid, userId)) {
1988 throw new SecurityException(
1989 String.format(
1990 "User %s tying remove account for %s" ,
1991 UserHandle.getCallingUserId(),
1992 userId));
1993 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001994 /*
1995 * Only the system or authenticator should be allowed to remove accounts for that
1996 * authenticator. This will let users remove accounts (via Settings in the system) but not
1997 * arbitrary applications (like competing authenticators).
1998 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001999 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002000 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
2001 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002002 String msg = String.format(
2003 "uid %s cannot remove accounts of type: %s",
2004 callingUid,
2005 account.type);
2006 throw new SecurityException(msg);
2007 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002008 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002009 try {
2010 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2011 "User cannot modify accounts");
2012 } catch (RemoteException re) {
2013 }
2014 return;
2015 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002016 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002017 try {
2018 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2019 "User cannot modify accounts of this type (policy).");
2020 } catch (RemoteException re) {
2021 }
2022 return;
2023 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002024 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002025 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002026 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002027 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002028 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002029 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002030 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002031 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002032 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002033 }
2034 }
2035 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002036 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002037 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002038 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2039 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002040 accountId,
2041 accounts,
2042 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002043 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002044 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2045 } finally {
2046 restoreCallingIdentity(identityToken);
2047 }
2048 }
2049
2050 @Override
2051 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002052 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002053 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2054 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002055 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002056 + ", pid " + Binder.getCallingPid());
2057 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002058 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002059 if (account == null) {
2060 /*
2061 * Null accounts should result in returning false, as per
2062 * AccountManage.addAccountExplicitly(...) java doc.
2063 */
2064 Log.e(TAG, "account is null");
2065 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002066 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002067 String msg = String.format(
2068 "uid %s cannot explicitly add accounts of type: %s",
2069 callingUid,
2070 account.type);
2071 throw new SecurityException(msg);
2072 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002073 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002074 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002075 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002076 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2077 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002078 accountId,
2079 accounts,
2080 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002081 long identityToken = clearCallingIdentity();
2082 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002083 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002084 } finally {
2085 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002086 }
Fred Quintana60307342009-03-24 22:48:12 -07002087 }
2088
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002089 private class RemoveAccountSession extends Session {
2090 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002091 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002092 Account account, boolean expectActivityLaunch) {
2093 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002094 true /* stripAuthTokenFromResult */, account.name,
2095 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002096 mAccount = account;
2097 }
2098
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002099 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002100 protected String toDebugString(long now) {
2101 return super.toDebugString(now) + ", removeAccount"
2102 + ", account " + mAccount;
2103 }
2104
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002105 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002106 public void run() throws RemoteException {
2107 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2108 }
2109
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002110 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002111 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002112 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002113 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2114 && !result.containsKey(AccountManager.KEY_INTENT)) {
2115 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002116 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002117 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002118 }
2119 IAccountManagerResponse response = getResponseAndClose();
2120 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002121 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2122 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2123 + response);
2124 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002125 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002126 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002127 try {
2128 response.onResult(result2);
2129 } catch (RemoteException e) {
2130 // ignore
2131 }
2132 }
2133 }
2134 super.onResult(result);
2135 }
2136 }
2137
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002138 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002139 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002140 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002141 }
2142
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002143 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002144 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002145 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002146 if (!userUnlocked) {
2147 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2148 + " is still locked. CE data will be removed later");
2149 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002150 synchronized (accounts.dbLock) {
2151 synchronized (accounts.cacheLock) {
2152 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2153 accounts);
2154 accounts.accountsDb.beginTransaction();
2155 // Set to a dummy value, this will only be used if the database
2156 // transaction succeeds.
2157 long accountId = -1;
2158 try {
2159 accountId = accounts.accountsDb.findDeAccountId(account);
2160 if (accountId >= 0) {
2161 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002162 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002163 // always delete from CE table if CE storage is available
2164 // DE account could be removed while CE was locked
2165 if (userUnlocked) {
2166 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2167 if (ceAccountId >= 0) {
2168 accounts.accountsDb.deleteCeAccount(ceAccountId);
2169 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002170 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002171 accounts.accountsDb.setTransactionSuccessful();
2172 } finally {
2173 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002174 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002175 if (isChanged) {
2176 removeAccountFromCacheLocked(accounts, account);
2177 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2178 .entrySet()) {
2179 if (packageToVisibility.getValue()
2180 != AccountManager.VISIBILITY_NOT_VISIBLE) {
2181 notifyPackage(packageToVisibility.getKey(), accounts);
2182 }
2183 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002184
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002185 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2186 sendAccountsChangedBroadcast(accounts.userId);
2187 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2188 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2189 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2190 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002191 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002192 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002193 long id = Binder.clearCallingIdentity();
2194 try {
2195 int parentUserId = accounts.userId;
2196 if (canHaveProfile(parentUserId)) {
2197 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002198 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002199 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002200 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002201 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002202 }
2203 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002204 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002205 } finally {
2206 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002207 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002208
2209 if (isChanged) {
2210 synchronized (accounts.credentialsPermissionNotificationIds) {
2211 for (Pair<Pair<Account, String>, Integer> key
2212 : accounts.credentialsPermissionNotificationIds.keySet()) {
2213 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002214 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002215 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002216 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002217 account, uid, false));
2218 }
2219 }
2220 }
2221 }
2222
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002223 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002224 }
2225
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002226 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002227 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002228 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002229 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2230 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002231 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2232 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002233 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002234 + ", pid " + Binder.getCallingPid());
2235 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002236 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002237 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002238 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002239 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002240 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002241 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002242 accounts.accountsDb.beginTransaction();
2243 try {
2244 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2245 accounts.accountsDb.setTransactionSuccessful();
2246 } finally {
2247 accounts.accountsDb.endTransaction();
2248 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002249 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002250 for (Pair<Account, String> tokenInfo : deletedTokens) {
2251 Account act = tokenInfo.first;
2252 String tokenType = tokenInfo.second;
2253 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002254 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002255 // wipe out cached token in memory.
2256 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002257 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002258 }
Fred Quintana60307342009-03-24 22:48:12 -07002259 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002260 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002261 }
2262 }
2263
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002264 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002265 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002266 // TODO Move to AccountsDB
2267 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002268 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002269
Fred Quintana33269202009-04-20 16:05:10 -07002270 try {
2271 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002272 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002273 String accountName = cursor.getString(1);
2274 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002275 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002276 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002277 }
Fred Quintana33269202009-04-20 16:05:10 -07002278 } finally {
2279 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002280 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002281 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002282 }
2283
Carlos Valdivia91979be2015-05-22 14:11:35 -07002284 private void saveCachedToken(
2285 UserAccounts accounts,
2286 Account account,
2287 String callerPkg,
2288 byte[] callerSigDigest,
2289 String tokenType,
2290 String token,
2291 long expiryMillis) {
2292
2293 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2294 return;
2295 }
2296 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002297 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002298 synchronized (accounts.cacheLock) {
2299 accounts.accountTokenCaches.put(
2300 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002301 }
2302 }
2303
Amith Yamasani04e0d262012-02-14 11:50:53 -08002304 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2305 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002306 if (account == null || type == null) {
2307 return false;
2308 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002309 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002310 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002311 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002312 accounts.accountsDb.beginTransaction();
2313 boolean updateCache = false;
2314 try {
2315 long accountId = accounts.accountsDb.findDeAccountId(account);
2316 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002317 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002318 }
2319 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2320 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2321 accounts.accountsDb.setTransactionSuccessful();
2322 updateCache = true;
2323 return true;
2324 }
2325 return false;
2326 } finally {
2327 accounts.accountsDb.endTransaction();
2328 if (updateCache) {
2329 synchronized (accounts.cacheLock) {
2330 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2331 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002332 }
Fred Quintana33269202009-04-20 16:05:10 -07002333 }
Fred Quintana60307342009-03-24 22:48:12 -07002334 }
2335 }
2336
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002337 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002338 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002339 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002340 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2341 Log.v(TAG, "peekAuthToken: " + account
2342 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002343 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002344 + ", pid " + Binder.getCallingPid());
2345 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002346 Preconditions.checkNotNull(account, "account cannot be null");
2347 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002348 int userId = UserHandle.getCallingUserId();
2349 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002350 String msg = String.format(
2351 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2352 callingUid,
2353 account.type);
2354 throw new SecurityException(msg);
2355 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002356 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002357 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2358 + callingUid);
2359 return null;
2360 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002361 long identityToken = clearCallingIdentity();
2362 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002363 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002364 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002365 } finally {
2366 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002367 }
Fred Quintana60307342009-03-24 22:48:12 -07002368 }
2369
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002370 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002371 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002372 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002373 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2374 Log.v(TAG, "setAuthToken: " + account
2375 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002376 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002377 + ", pid " + Binder.getCallingPid());
2378 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002379 Preconditions.checkNotNull(account, "account cannot be null");
2380 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002381 int userId = UserHandle.getCallingUserId();
2382 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002383 String msg = String.format(
2384 "uid %s cannot set auth tokens associated with accounts of type: %s",
2385 callingUid,
2386 account.type);
2387 throw new SecurityException(msg);
2388 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002389 long identityToken = clearCallingIdentity();
2390 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002391 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002392 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002393 } finally {
2394 restoreCallingIdentity(identityToken);
2395 }
Fred Quintana60307342009-03-24 22:48:12 -07002396 }
2397
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002398 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002399 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002400 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002401 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2402 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002403 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002404 + ", pid " + Binder.getCallingPid());
2405 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002406 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002407 int userId = UserHandle.getCallingUserId();
2408 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002409 String msg = String.format(
2410 "uid %s cannot set secrets for accounts of type: %s",
2411 callingUid,
2412 account.type);
2413 throw new SecurityException(msg);
2414 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002415 long identityToken = clearCallingIdentity();
2416 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002417 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002418 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002419 } finally {
2420 restoreCallingIdentity(identityToken);
2421 }
Fred Quintana60307342009-03-24 22:48:12 -07002422 }
2423
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002424 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2425 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002426 if (account == null) {
2427 return;
2428 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002429 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002430 synchronized (accounts.dbLock) {
2431 synchronized (accounts.cacheLock) {
2432 accounts.accountsDb.beginTransaction();
2433 try {
2434 final long accountId = accounts.accountsDb.findDeAccountId(account);
2435 if (accountId >= 0) {
2436 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2437 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2438 accounts.authTokenCache.remove(account);
2439 accounts.accountTokenCaches.remove(account);
2440 accounts.accountsDb.setTransactionSuccessful();
2441 // If there is an account whose password will be updated and the database
2442 // transactions succeed, then we say that a change has occured. Even if the
2443 // new password is the same as the old and there were no authtokens to
2444 // delete.
2445 isChanged = true;
2446 String action = (password == null || password.length() == 0) ?
2447 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2448 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2449 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2450 callingUid);
2451 }
2452 } finally {
2453 accounts.accountsDb.endTransaction();
2454 if (isChanged) {
2455 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2456 sendNotificationAccountUpdated(account, accounts);
2457 sendAccountsChangedBroadcast(accounts.userId);
2458 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002459 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002460 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002461 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002462 }
2463
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002464 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002465 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002466 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002467 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2468 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002469 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002470 + ", pid " + Binder.getCallingPid());
2471 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002472 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002473 int userId = UserHandle.getCallingUserId();
2474 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002475 String msg = String.format(
2476 "uid %s cannot clear passwords for accounts of type: %s",
2477 callingUid,
2478 account.type);
2479 throw new SecurityException(msg);
2480 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002481 long identityToken = clearCallingIdentity();
2482 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002483 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002484 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002485 } finally {
2486 restoreCallingIdentity(identityToken);
2487 }
Fred Quintana60307342009-03-24 22:48:12 -07002488 }
2489
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002490 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002491 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002492 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002493 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2494 Log.v(TAG, "setUserData: " + account
2495 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002496 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002497 + ", pid " + Binder.getCallingPid());
2498 }
Fred Quintana382601f2010-03-25 12:25:10 -07002499 if (key == null) throw new IllegalArgumentException("key is null");
2500 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002501 int userId = UserHandle.getCallingUserId();
2502 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002503 String msg = String.format(
2504 "uid %s cannot set user data for accounts of type: %s",
2505 callingUid,
2506 account.type);
2507 throw new SecurityException(msg);
2508 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002509 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002510 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002511 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002512 synchronized (accounts.dbLock) {
2513 synchronized (accounts.cacheLock) {
2514 if (!accountExistsCacheLocked(accounts, account)) {
2515 return;
2516 }
2517 setUserdataInternalLocked(accounts, account, key, value);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002518 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002519 }
Fred Quintana60307342009-03-24 22:48:12 -07002520 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002521 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002522 }
2523 }
2524
Simranjit Kohli858511c2016-03-10 18:36:11 +00002525 private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
2526 if (accounts.accountCache.containsKey(account.type)) {
2527 for (Account acc : accounts.accountCache.get(account.type)) {
2528 if (acc.name.equals(account.name)) {
2529 return true;
2530 }
2531 }
2532 }
2533 return false;
2534 }
2535
2536 private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002537 String value) {
Fred Quintana31957f12009-10-21 13:43:10 -07002538 if (account == null || key == null) {
2539 return;
2540 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002541 accounts.accountsDb.beginTransaction();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002542 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002543 long accountId = accounts.accountsDb.findDeAccountId(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002544 if (accountId < 0) {
2545 return;
2546 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002547 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002548 if (extrasId < 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002549 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002550 if (extrasId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002551 return;
2552 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002553 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002554 return;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002555 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002556 writeUserDataIntoCacheLocked(accounts, account, key, value);
2557 accounts.accountsDb.setTransactionSuccessful();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002558 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002559 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002560 }
2561 }
2562
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002563 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002564 if (result == null) {
2565 Log.e(TAG, "the result is unexpectedly null", new Exception());
2566 }
2567 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2568 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2569 + response);
2570 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002571 try {
2572 response.onResult(result);
2573 } catch (RemoteException e) {
2574 // if the caller is dead then there is no one to care about remote
2575 // exceptions
2576 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2577 Log.v(TAG, "failure while notifying response", e);
2578 }
2579 }
2580 }
2581
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002582 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002583 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2584 final String authTokenType)
2585 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002586 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2587 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002588
Fred Quintanad9640ec2012-05-23 12:37:00 -07002589 final int callingUid = getCallingUid();
2590 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002591 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002592 throw new SecurityException("can only call from system");
2593 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002594 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002595 long identityToken = clearCallingIdentity();
2596 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002597 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002598 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2599 false /* stripAuthTokenFromResult */, null /* accountName */,
2600 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002601 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002602 protected String toDebugString(long now) {
2603 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002604 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002605 + ", authTokenType " + authTokenType;
2606 }
2607
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002608 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002609 public void run() throws RemoteException {
2610 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2611 }
2612
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002613 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002614 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002615 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002616 if (result != null) {
2617 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2618 Bundle bundle = new Bundle();
2619 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2620 super.onResult(bundle);
2621 return;
2622 } else {
2623 super.onResult(result);
2624 }
2625 }
2626 }.bind();
2627 } finally {
2628 restoreCallingIdentity(identityToken);
2629 }
2630 }
2631
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002632 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002633 public void getAuthToken(
2634 IAccountManagerResponse response,
2635 final Account account,
2636 final String authTokenType,
2637 final boolean notifyOnAuthFailure,
2638 final boolean expectActivityLaunch,
2639 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002640 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002641 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2642 Log.v(TAG, "getAuthToken: " + account
2643 + ", response " + response
2644 + ", authTokenType " + authTokenType
2645 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2646 + ", expectActivityLaunch " + expectActivityLaunch
2647 + ", caller's uid " + Binder.getCallingUid()
2648 + ", pid " + Binder.getCallingPid());
2649 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002650 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002651 try {
2652 if (account == null) {
2653 Slog.w(TAG, "getAuthToken called with null account");
2654 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2655 return;
2656 }
2657 if (authTokenType == null) {
2658 Slog.w(TAG, "getAuthToken called with null authTokenType");
2659 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2660 return;
2661 }
2662 } catch (RemoteException e) {
2663 Slog.w(TAG, "Failed to report error back to the client." + e);
2664 return;
2665 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002666 int userId = UserHandle.getCallingUserId();
2667 long ident = Binder.clearCallingIdentity();
2668 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002669 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002670 try {
2671 accounts = getUserAccounts(userId);
2672 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2673 AuthenticatorDescription.newKey(account.type), accounts.userId);
2674 } finally {
2675 Binder.restoreCallingIdentity(ident);
2676 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002677
Costin Manolachea40c6302010-12-13 14:50:45 -08002678 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002679 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002680
2681 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002682 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002683 final boolean permissionGranted =
2684 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002685
Carlos Valdivia91979be2015-05-22 14:11:35 -07002686 // Get the calling package. We will use it for the purpose of caching.
2687 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002688 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002689 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002690 try {
2691 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2692 } finally {
2693 Binder.restoreCallingIdentity(ident);
2694 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002695 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2696 String msg = String.format(
2697 "Uid %s is attempting to illegally masquerade as package %s!",
2698 callerUid,
2699 callerPkg);
2700 throw new SecurityException(msg);
2701 }
2702
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002703 // let authenticator know the identity of the caller
2704 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2705 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002706
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002707 if (notifyOnAuthFailure) {
2708 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002709 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002710
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002711 long identityToken = clearCallingIdentity();
2712 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002713 // Distill the caller's package signatures into a single digest.
2714 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2715
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002716 // if the caller has permission, do the peek. otherwise go the more expensive
2717 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002718 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002719 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002720 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002721 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002722 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2723 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2724 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002725 onResult(response, result);
2726 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002727 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002728 }
2729
Carlos Valdivia91979be2015-05-22 14:11:35 -07002730 if (customTokens) {
2731 /*
2732 * Look up tokens in the new cache only if the loginOptions don't have parameters
2733 * outside of those expected to be injected by the AccountManager, e.g.
2734 * ANDORID_PACKAGE_NAME.
2735 */
2736 String token = readCachedTokenInternal(
2737 accounts,
2738 account,
2739 authTokenType,
2740 callerPkg,
2741 callerPkgSigDigest);
2742 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002743 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2744 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2745 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002746 Bundle result = new Bundle();
2747 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2748 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2749 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2750 onResult(response, result);
2751 return;
2752 }
2753 }
2754
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002755 new Session(
2756 accounts,
2757 response,
2758 account.type,
2759 expectActivityLaunch,
2760 false /* stripAuthTokenFromResult */,
2761 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002762 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002763 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002764 protected String toDebugString(long now) {
2765 if (loginOptions != null) loginOptions.keySet();
2766 return super.toDebugString(now) + ", getAuthToken"
2767 + ", " + account
2768 + ", authTokenType " + authTokenType
2769 + ", loginOptions " + loginOptions
2770 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2771 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002772
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002773 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002774 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002775 // If the caller doesn't have permission then create and return the
2776 // "grant permission" intent instead of the "getAuthToken" intent.
2777 if (!permissionGranted) {
2778 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2779 } else {
2780 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2781 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002782 }
2783
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002784 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002785 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002786 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002787 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002788 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002789 Intent intent = newGrantCredentialsPermissionIntent(
2790 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002791 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002792 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002793 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002794 authTokenType,
2795 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002796 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002797 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002798 onResult(bundle);
2799 return;
2800 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002801 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002802 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002803 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2804 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002805 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002806 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002807 "the type and name should not be empty");
2808 return;
2809 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002810 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002811 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002812 saveAuthTokenToDatabase(
2813 mAccounts,
2814 resultAccount,
2815 authTokenType,
2816 authToken);
2817 }
2818 long expiryMillis = result.getLong(
2819 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2820 if (customTokens
2821 && expiryMillis > System.currentTimeMillis()) {
2822 saveCachedToken(
2823 mAccounts,
2824 account,
2825 callerPkg,
2826 callerPkgSigDigest,
2827 authTokenType,
2828 authToken,
2829 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002830 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002831 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002832
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002833 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002834 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002835 /*
2836 * Make sure that the supplied intent is owned by the authenticator
2837 * giving it to the system. Otherwise a malicious authenticator could
2838 * have users launching arbitrary activities by tricking users to
2839 * interact with malicious notifications.
2840 */
2841 checkKeyIntent(
2842 Binder.getCallingUid(),
2843 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002844 doNotification(
2845 mAccounts,
2846 account,
2847 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002848 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002849 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002850 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002851 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002852 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002853 }.bind();
2854 } finally {
2855 restoreCallingIdentity(identityToken);
2856 }
Fred Quintana60307342009-03-24 22:48:12 -07002857 }
2858
Carlos Valdivia91979be2015-05-22 14:11:35 -07002859 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2860 MessageDigest digester;
2861 try {
2862 digester = MessageDigest.getInstance("SHA-256");
2863 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2864 callerPkg, PackageManager.GET_SIGNATURES);
2865 for (Signature sig : pkgInfo.signatures) {
2866 digester.update(sig.toByteArray());
2867 }
2868 } catch (NoSuchAlgorithmException x) {
2869 Log.wtf(TAG, "SHA-256 should be available", x);
2870 digester = null;
2871 } catch (NameNotFoundException e) {
2872 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2873 digester = null;
2874 }
2875 return (digester == null) ? null : digester.digest();
2876 }
2877
Dianne Hackborn41203752012-08-31 14:05:51 -07002878 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002879 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002880 int uid = intent.getIntExtra(
2881 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2882 String authTokenType = intent.getStringExtra(
2883 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002884 final String titleAndSubtitle =
2885 mContext.getString(R.string.permission_request_notification_with_subtitle,
2886 account.name);
2887 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002888 String title = titleAndSubtitle;
2889 String subtitle = "";
2890 if (index > 0) {
2891 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002892 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002893 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002894 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002895 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05002896 Notification n =
2897 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
2898 .setSmallIcon(android.R.drawable.stat_sys_warning)
2899 .setWhen(0)
2900 .setColor(contextForUser.getColor(
2901 com.android.internal.R.color.system_notification_accent_color))
2902 .setContentTitle(title)
2903 .setContentText(subtitle)
2904 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2905 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2906 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002907 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002908 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002909 }
2910
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002911 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2912 int uid, AccountAuthenticatorResponse response, String authTokenType,
2913 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002914
2915 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002916
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002917 if (startInNewTask) {
2918 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2919 // Since it was set in Eclair+ we can't change it without breaking apps using
2920 // the intent from a non-Activity context. This is the default behavior.
2921 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2922 }
2923 intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
2924 authTokenType, uid) + (packageName != null ? packageName : "")));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002925 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002926 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2927 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002928 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002929
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002930 return intent;
2931 }
2932
2933 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2934 int uid) {
2935 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002936 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002937 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002938 final Pair<Pair<Account, String>, Integer> key =
2939 new Pair<Pair<Account, String>, Integer>(
2940 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002941 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002942 if (id == null) {
2943 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002944 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002945 }
2946 }
2947 return id;
2948 }
2949
Amith Yamasani04e0d262012-02-14 11:50:53 -08002950 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002951 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002952 synchronized (accounts.signinRequiredNotificationIds) {
2953 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002954 if (id == null) {
2955 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002956 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002957 }
2958 }
2959 return id;
2960 }
2961
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002962 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002963 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002964 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002965 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002966 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002967 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2968 Log.v(TAG, "addAccount: accountType " + accountType
2969 + ", response " + response
2970 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002971 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002972 + ", expectActivityLaunch " + expectActivityLaunch
2973 + ", caller's uid " + Binder.getCallingUid()
2974 + ", pid " + Binder.getCallingPid());
2975 }
Fred Quintana382601f2010-03-25 12:25:10 -07002976 if (response == null) throw new IllegalArgumentException("response is null");
2977 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002978
Amith Yamasani71e6c692013-03-24 17:39:28 -07002979 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002980 final int uid = Binder.getCallingUid();
2981 final int userId = UserHandle.getUserId(uid);
2982 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002983 try {
2984 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2985 "User is not allowed to add an account!");
2986 } catch (RemoteException re) {
2987 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002988 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002989 return;
2990 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002991 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002992 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002993 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2994 "User cannot modify accounts of this type (policy).");
2995 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002996 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002997 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2998 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002999 return;
3000 }
3001
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003002 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003003 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3004 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3005 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3006
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003007 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003008 long identityToken = clearCallingIdentity();
3009 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003010 UserAccounts accounts = getUserAccounts(usrId);
3011 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003012 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3013 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003014 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003015 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003016 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003017 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003018 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003019 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003020 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003021 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003022
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003023 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003024 protected String toDebugString(long now) {
3025 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003026 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003027 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003028 }
3029 }.bind();
3030 } finally {
3031 restoreCallingIdentity(identityToken);
3032 }
Fred Quintana60307342009-03-24 22:48:12 -07003033 }
3034
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003035 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003036 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3037 final String authTokenType, final String[] requiredFeatures,
3038 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003039 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003040 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003041 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3042 Log.v(TAG, "addAccount: accountType " + accountType
3043 + ", response " + response
3044 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003045 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003046 + ", expectActivityLaunch " + expectActivityLaunch
3047 + ", caller's uid " + Binder.getCallingUid()
3048 + ", pid " + Binder.getCallingPid()
3049 + ", for user id " + userId);
3050 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003051 Preconditions.checkArgument(response != null, "response cannot be null");
3052 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003053 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003054 if (isCrossUser(callingUid, userId)) {
3055 throw new SecurityException(
3056 String.format(
3057 "User %s trying to add account for %s" ,
3058 UserHandle.getCallingUserId(),
3059 userId));
3060 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003061
3062 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003063 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003064 try {
3065 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3066 "User is not allowed to add an account!");
3067 } catch (RemoteException re) {
3068 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003069 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003070 return;
3071 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003072 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003073 try {
3074 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3075 "User cannot modify accounts of this type (policy).");
3076 } catch (RemoteException re) {
3077 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003078 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3079 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003080 return;
3081 }
3082
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003083 final int pid = Binder.getCallingPid();
3084 final int uid = Binder.getCallingUid();
3085 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3086 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3087 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3088
3089 long identityToken = clearCallingIdentity();
3090 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003091 UserAccounts accounts = getUserAccounts(userId);
3092 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003093 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3094 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003095 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003096 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003097 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003098 @Override
3099 public void run() throws RemoteException {
3100 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3101 options);
3102 }
3103
3104 @Override
3105 protected String toDebugString(long now) {
3106 return super.toDebugString(now) + ", addAccount"
3107 + ", accountType " + accountType
3108 + ", requiredFeatures "
3109 + (requiredFeatures != null
3110 ? TextUtils.join(",", requiredFeatures)
3111 : null);
3112 }
3113 }.bind();
3114 } finally {
3115 restoreCallingIdentity(identityToken);
3116 }
3117 }
3118
Sandra Kwan78812282015-11-04 11:19:47 -08003119 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003120 public void startAddAccountSession(
3121 final IAccountManagerResponse response,
3122 final String accountType,
3123 final String authTokenType,
3124 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003125 final boolean expectActivityLaunch,
3126 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003127 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003128 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3129 Log.v(TAG,
3130 "startAddAccountSession: accountType " + accountType
3131 + ", response " + response
3132 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003133 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003134 + ", expectActivityLaunch " + expectActivityLaunch
3135 + ", caller's uid " + Binder.getCallingUid()
3136 + ", pid " + Binder.getCallingPid());
3137 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003138 Preconditions.checkArgument(response != null, "response cannot be null");
3139 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003140
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003141 final int uid = Binder.getCallingUid();
3142 final int userId = UserHandle.getUserId(uid);
3143 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003144 try {
3145 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3146 "User is not allowed to add an account!");
3147 } catch (RemoteException re) {
3148 }
3149 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3150 return;
3151 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003152 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003153 try {
3154 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3155 "User cannot modify accounts of this type (policy).");
3156 } catch (RemoteException re) {
3157 }
3158 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3159 userId);
3160 return;
3161 }
Sandra Kwan78812282015-11-04 11:19:47 -08003162 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003163 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3164 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3165 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3166
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003167 // Check to see if the Password should be included to the caller.
3168 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3169 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003170 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003171
Sandra Kwan78812282015-11-04 11:19:47 -08003172 long identityToken = clearCallingIdentity();
3173 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003174 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003175 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3176 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003177 new StartAccountSession(
3178 accounts,
3179 response,
3180 accountType,
3181 expectActivityLaunch,
3182 null /* accountName */,
3183 false /* authDetailsRequired */,
3184 true /* updateLastAuthenticationTime */,
3185 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003186 @Override
3187 public void run() throws RemoteException {
3188 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3189 requiredFeatures, options);
3190 }
3191
3192 @Override
3193 protected String toDebugString(long now) {
3194 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3195 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3196 + accountType + ", requiredFeatures "
3197 + (requiredFeatures != null ? requiredFeaturesStr : null);
3198 }
3199 }.bind();
3200 } finally {
3201 restoreCallingIdentity(identityToken);
3202 }
3203 }
3204
3205 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3206 private abstract class StartAccountSession extends Session {
3207
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003208 private final boolean mIsPasswordForwardingAllowed;
3209
3210 public StartAccountSession(
3211 UserAccounts accounts,
3212 IAccountManagerResponse response,
3213 String accountType,
3214 boolean expectActivityLaunch,
3215 String accountName,
3216 boolean authDetailsRequired,
3217 boolean updateLastAuthenticationTime,
3218 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003219 super(accounts, response, accountType, expectActivityLaunch,
3220 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3221 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003222 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003223 }
3224
3225 @Override
3226 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003227 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003228 mNumResults++;
3229 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003230 if (result != null
3231 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003232 checkKeyIntent(
3233 Binder.getCallingUid(),
3234 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003235 }
Sandra Kwan78812282015-11-04 11:19:47 -08003236 IAccountManagerResponse response;
3237 if (mExpectActivityLaunch && result != null
3238 && result.containsKey(AccountManager.KEY_INTENT)) {
3239 response = mResponse;
3240 } else {
3241 response = getResponseAndClose();
3242 }
3243 if (response == null) {
3244 return;
3245 }
3246 if (result == null) {
3247 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3248 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3249 + response);
3250 }
3251 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3252 "null bundle returned");
3253 return;
3254 }
3255
3256 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3257 // All AccountManager error codes are greater
3258 // than 0
3259 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3260 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3261 return;
3262 }
3263
Hongming Jin368aa192016-07-29 14:29:54 -07003264 // Omit passwords if the caller isn't permitted to see them.
3265 if (!mIsPasswordForwardingAllowed) {
3266 result.remove(AccountManager.KEY_PASSWORD);
3267 }
3268
Sandra Kwan78812282015-11-04 11:19:47 -08003269 // Strip auth token from result.
3270 result.remove(AccountManager.KEY_AUTHTOKEN);
3271
3272 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3273 Log.v(TAG,
3274 getClass().getSimpleName() + " calling onResult() on response " + response);
3275 }
3276
3277 // Get the session bundle created by authenticator. The
3278 // bundle contains data necessary for finishing the session
3279 // later. The session bundle will be encrypted here and
3280 // decrypted later when trying to finish the session.
3281 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3282 if (sessionBundle != null) {
3283 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3284 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003285 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003286 Log.w(TAG, "Account type in session bundle doesn't match request.");
3287 }
3288 // Add accountType info to session bundle. This will
3289 // override any value set by authenticator.
3290 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3291
3292 // Encrypt session bundle before returning to caller.
3293 try {
3294 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3295 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3296 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3297 } catch (GeneralSecurityException e) {
3298 if (Log.isLoggable(TAG, Log.DEBUG)) {
3299 Log.v(TAG, "Failed to encrypt session bundle!", e);
3300 }
3301 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3302 "failed to encrypt session bundle");
3303 return;
3304 }
3305 }
3306
3307 sendResponse(response, result);
3308 }
3309 }
3310
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003311 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003312 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003313 @NonNull Bundle sessionBundle,
3314 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003315 Bundle appInfo,
3316 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003317 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003318 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003319 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3320 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003321 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003322 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003323 + ", caller's uid " + callingUid
3324 + ", caller's user id " + UserHandle.getCallingUserId()
3325 + ", pid " + Binder.getCallingPid()
3326 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003327 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003328 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003329 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3330 // Account type is added to it before encryption.
3331 if (sessionBundle == null || sessionBundle.size() == 0) {
3332 throw new IllegalArgumentException("sessionBundle is empty");
3333 }
3334
Dmitry Dementyev52745472016-12-02 10:27:45 -08003335 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003336 if (isCrossUser(callingUid, userId)) {
3337 throw new SecurityException(
3338 String.format(
3339 "User %s trying to finish session for %s without cross user permission",
3340 UserHandle.getCallingUserId(),
3341 userId));
3342 }
3343
Sandra Kwan0b84b452016-01-20 15:25:42 -08003344 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003345 sendErrorResponse(response,
3346 AccountManager.ERROR_CODE_USER_RESTRICTED,
3347 "User is not allowed to add an account!");
3348 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3349 return;
3350 }
3351
3352 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003353 final Bundle decryptedBundle;
3354 final String accountType;
3355 // First decrypt session bundle to get account type for checking permission.
3356 try {
3357 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3358 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3359 if (decryptedBundle == null) {
3360 sendErrorResponse(
3361 response,
3362 AccountManager.ERROR_CODE_BAD_REQUEST,
3363 "failed to decrypt session bundle");
3364 return;
3365 }
3366 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3367 // Account type cannot be null. This should not happen if session bundle was created
3368 // properly by #StartAccountSession.
3369 if (TextUtils.isEmpty(accountType)) {
3370 sendErrorResponse(
3371 response,
3372 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3373 "accountType is empty");
3374 return;
3375 }
3376
3377 // If by any chances, decryptedBundle contains colliding keys with
3378 // system info
3379 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3380 // update credentials flow, we should replace with the new values of the current call.
3381 if (appInfo != null) {
3382 decryptedBundle.putAll(appInfo);
3383 }
3384
3385 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003386 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003387 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3388 } catch (GeneralSecurityException e) {
3389 if (Log.isLoggable(TAG, Log.DEBUG)) {
3390 Log.v(TAG, "Failed to decrypt session bundle!", e);
3391 }
3392 sendErrorResponse(
3393 response,
3394 AccountManager.ERROR_CODE_BAD_REQUEST,
3395 "failed to decrypt session bundle");
3396 return;
3397 }
3398
Sandra Kwan0b84b452016-01-20 15:25:42 -08003399 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003400 sendErrorResponse(
3401 response,
3402 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3403 "User cannot modify accounts of this type (policy).");
3404 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3405 userId);
3406 return;
3407 }
3408
3409 long identityToken = clearCallingIdentity();
3410 try {
3411 UserAccounts accounts = getUserAccounts(userId);
3412 logRecordWithUid(
3413 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003414 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3415 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003416 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003417 new Session(
3418 accounts,
3419 response,
3420 accountType,
3421 expectActivityLaunch,
3422 true /* stripAuthTokenFromResult */,
3423 null /* accountName */,
3424 false /* authDetailsRequired */,
3425 true /* updateLastAuthenticationTime */) {
3426 @Override
3427 public void run() throws RemoteException {
3428 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3429 }
3430
3431 @Override
3432 protected String toDebugString(long now) {
3433 return super.toDebugString(now)
3434 + ", finishSession"
3435 + ", accountType " + accountType;
3436 }
3437 }.bind();
3438 } finally {
3439 restoreCallingIdentity(identityToken);
3440 }
3441 }
3442
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003443 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003444 final DevicePolicyManagerInternal dpmi =
3445 LocalServices.getService(DevicePolicyManagerInternal.class);
3446 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003447 if (dpmi == null) {
3448 intent = getDefaultCantAddAccountIntent(errorCode);
3449 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003450 intent = dpmi.createUserRestrictionSupportIntent(userId,
3451 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3452 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3453 intent = dpmi.createShowAdminSupportIntent(userId, false);
3454 }
3455 if (intent == null) {
3456 intent = getDefaultCantAddAccountIntent(errorCode);
3457 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003458 long identityToken = clearCallingIdentity();
3459 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003460 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003461 } finally {
3462 restoreCallingIdentity(identityToken);
3463 }
3464 }
3465
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003466 /**
3467 * Called when we don't know precisely who is preventing us from adding an account.
3468 */
3469 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3470 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3471 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3472 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3473 return cantAddAccount;
3474 }
3475
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003476 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003477 public void confirmCredentialsAsUser(
3478 IAccountManagerResponse response,
3479 final Account account,
3480 final Bundle options,
3481 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003482 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003483 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003484 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003485 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3486 Log.v(TAG, "confirmCredentials: " + account
3487 + ", response " + response
3488 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003489 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003490 + ", pid " + Binder.getCallingPid());
3491 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003492 // Only allow the system process to read accounts of other users
3493 if (isCrossUser(callingUid, userId)) {
3494 throw new SecurityException(
3495 String.format(
3496 "User %s trying to confirm account credentials for %s" ,
3497 UserHandle.getCallingUserId(),
3498 userId));
3499 }
Fred Quintana382601f2010-03-25 12:25:10 -07003500 if (response == null) throw new IllegalArgumentException("response is null");
3501 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003502 long identityToken = clearCallingIdentity();
3503 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003504 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003505 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003506 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003507 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003508 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003509 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003510 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003511 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003512 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003513 protected String toDebugString(long now) {
3514 return super.toDebugString(now) + ", confirmCredentials"
3515 + ", " + account;
3516 }
3517 }.bind();
3518 } finally {
3519 restoreCallingIdentity(identityToken);
3520 }
Fred Quintana60307342009-03-24 22:48:12 -07003521 }
3522
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003523 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003524 public void updateCredentials(IAccountManagerResponse response, final Account account,
3525 final String authTokenType, final boolean expectActivityLaunch,
3526 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003527 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003528 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3529 Log.v(TAG, "updateCredentials: " + account
3530 + ", response " + response
3531 + ", authTokenType " + authTokenType
3532 + ", expectActivityLaunch " + expectActivityLaunch
3533 + ", caller's uid " + Binder.getCallingUid()
3534 + ", pid " + Binder.getCallingPid());
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");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003538 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003539 long identityToken = clearCallingIdentity();
3540 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003541 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003542 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003543 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003544 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003545 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003546 public void run() throws RemoteException {
3547 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3548 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003549 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003550 protected String toDebugString(long now) {
3551 if (loginOptions != null) loginOptions.keySet();
3552 return super.toDebugString(now) + ", updateCredentials"
3553 + ", " + account
3554 + ", authTokenType " + authTokenType
3555 + ", loginOptions " + loginOptions;
3556 }
3557 }.bind();
3558 } finally {
3559 restoreCallingIdentity(identityToken);
3560 }
Fred Quintana60307342009-03-24 22:48:12 -07003561 }
3562
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003563 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003564 public void startUpdateCredentialsSession(
3565 IAccountManagerResponse response,
3566 final Account account,
3567 final String authTokenType,
3568 final boolean expectActivityLaunch,
3569 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003570 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003571 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3572 Log.v(TAG,
3573 "startUpdateCredentialsSession: " + account + ", response " + response
3574 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3575 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3576 + ", pid " + Binder.getCallingPid());
3577 }
3578 if (response == null) {
3579 throw new IllegalArgumentException("response is null");
3580 }
3581 if (account == null) {
3582 throw new IllegalArgumentException("account is null");
3583 }
Sandra Kwana578d112015-12-16 16:01:43 -08003584
3585 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003586 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003587
3588 // Check to see if the Password should be included to the caller.
3589 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3590 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003591 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003592
Sandra Kwane68c37e2015-11-12 17:11:49 -08003593 long identityToken = clearCallingIdentity();
3594 try {
3595 UserAccounts accounts = getUserAccounts(userId);
3596 new StartAccountSession(
3597 accounts,
3598 response,
3599 account.type,
3600 expectActivityLaunch,
3601 account.name,
3602 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003603 true /* updateLastCredentialTime */,
3604 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003605 @Override
3606 public void run() throws RemoteException {
3607 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3608 loginOptions);
3609 }
3610
3611 @Override
3612 protected String toDebugString(long now) {
3613 if (loginOptions != null)
3614 loginOptions.keySet();
3615 return super.toDebugString(now)
3616 + ", startUpdateCredentialsSession"
3617 + ", " + account
3618 + ", authTokenType " + authTokenType
3619 + ", loginOptions " + loginOptions;
3620 }
3621 }.bind();
3622 } finally {
3623 restoreCallingIdentity(identityToken);
3624 }
3625 }
3626
3627 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003628 public void isCredentialsUpdateSuggested(
3629 IAccountManagerResponse response,
3630 final Account account,
3631 final String statusToken) {
3632 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3633 Log.v(TAG,
3634 "isCredentialsUpdateSuggested: " + account + ", response " + response
3635 + ", caller's uid " + Binder.getCallingUid()
3636 + ", pid " + Binder.getCallingPid());
3637 }
3638 if (response == null) {
3639 throw new IllegalArgumentException("response is null");
3640 }
3641 if (account == null) {
3642 throw new IllegalArgumentException("account is null");
3643 }
3644 if (TextUtils.isEmpty(statusToken)) {
3645 throw new IllegalArgumentException("status token is empty");
3646 }
3647
Sandra Kwan390c9d22016-01-12 14:13:37 -08003648 int usrId = UserHandle.getCallingUserId();
3649 long identityToken = clearCallingIdentity();
3650 try {
3651 UserAccounts accounts = getUserAccounts(usrId);
3652 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3653 false /* stripAuthTokenFromResult */, account.name,
3654 false /* authDetailsRequired */) {
3655 @Override
3656 protected String toDebugString(long now) {
3657 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3658 + ", " + account;
3659 }
3660
3661 @Override
3662 public void run() throws RemoteException {
3663 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3664 }
3665
3666 @Override
3667 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003668 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003669 IAccountManagerResponse response = getResponseAndClose();
3670 if (response == null) {
3671 return;
3672 }
3673
3674 if (result == null) {
3675 sendErrorResponse(
3676 response,
3677 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3678 "null bundle");
3679 return;
3680 }
3681
3682 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3683 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3684 + response);
3685 }
3686 // Check to see if an error occurred. We know if an error occurred because all
3687 // error codes are greater than 0.
3688 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3689 sendErrorResponse(response,
3690 result.getInt(AccountManager.KEY_ERROR_CODE),
3691 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3692 return;
3693 }
3694 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3695 sendErrorResponse(
3696 response,
3697 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3698 "no result in response");
3699 return;
3700 }
3701 final Bundle newResult = new Bundle();
3702 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3703 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3704 sendResponse(response, newResult);
3705 }
3706 }.bind();
3707 } finally {
3708 restoreCallingIdentity(identityToken);
3709 }
3710 }
3711
3712 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003713 public void editProperties(IAccountManagerResponse response, final String accountType,
3714 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003715 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003716 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3717 Log.v(TAG, "editProperties: accountType " + accountType
3718 + ", response " + response
3719 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003720 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003721 + ", pid " + Binder.getCallingPid());
3722 }
Fred Quintana382601f2010-03-25 12:25:10 -07003723 if (response == null) throw new IllegalArgumentException("response is null");
3724 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003725 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003726 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3727 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003728 String msg = String.format(
3729 "uid %s cannot edit authenticator properites for account type: %s",
3730 callingUid,
3731 accountType);
3732 throw new SecurityException(msg);
3733 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003734 long identityToken = clearCallingIdentity();
3735 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003736 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003737 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003738 true /* stripAuthTokenFromResult */, null /* accountName */,
3739 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003740 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003741 public void run() throws RemoteException {
3742 mAuthenticator.editProperties(this, mAccountType);
3743 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003744 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003745 protected String toDebugString(long now) {
3746 return super.toDebugString(now) + ", editProperties"
3747 + ", accountType " + accountType;
3748 }
3749 }.bind();
3750 } finally {
3751 restoreCallingIdentity(identityToken);
3752 }
Fred Quintana60307342009-03-24 22:48:12 -07003753 }
3754
Amith Yamasani12747872015-12-07 14:19:49 -08003755 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003756 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3757 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003758 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003759 throw new SecurityException("Can be called only by system UID");
3760 }
3761 Preconditions.checkNotNull(account, "account cannot be null");
3762 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3763 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3764
3765 final int userId = userHandle.getIdentifier();
3766
3767 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3768
3769 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003770 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003771 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003772 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003773 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003774 return false;
3775 }
3776 }
3777
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003778 // Returns package with oldest target SDK for given UID.
3779 private String getPackageNameForUid(int uid) {
3780 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3781 if (ArrayUtils.isEmpty(packageNames)) {
3782 return null;
3783 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003784 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003785 if (packageNames.length == 1) {
3786 return packageName;
3787 }
3788 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003789 int oldestVersion = Integer.MAX_VALUE;
3790 for (String name : packageNames) {
3791 try {
3792 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3793 if (applicationInfo != null) {
3794 int version = applicationInfo.targetSdkVersion;
3795 if (version < oldestVersion) {
3796 oldestVersion = version;
3797 packageName = name;
3798 }
3799 }
3800 } catch (NameNotFoundException e) {
3801 // skip
3802 }
3803 }
3804 return packageName;
3805 }
3806
Svet Ganovf6d424f12016-09-20 20:18:53 -07003807 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3808 int uid) {
3809 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003810 packageName = getPackageNameForUid(uid);
3811 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003812 return false;
3813 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003814 }
3815
3816 // Use null token which means any token. Having a token means the package
3817 // is trusted by the authenticator, hence it is fine to access the account.
3818 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3819 return true;
3820 }
3821 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003822 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003823
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003824 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003825 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003826 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003827 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003828 }
3829
3830 @Override
3831 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3832 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003833 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003834 throw new SecurityException("Can be called only by system UID");
3835 }
3836
3837 Preconditions.checkNotNull(account, "account cannot be null");
3838 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3839 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3840
3841 final int userId = userHandle.getIdentifier();
3842
3843 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3844
3845 final int uid;
3846 try {
3847 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3848 } catch (NameNotFoundException e) {
3849 Slog.e(TAG, "Unknown package " + packageName);
3850 return null;
3851 }
3852
3853 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3854
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003855 final long identity = Binder.clearCallingIdentity();
3856 try {
3857 return PendingIntent.getActivityAsUser(
3858 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3859 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3860 null, new UserHandle(userId)).getIntentSender();
3861 } finally {
3862 Binder.restoreCallingIdentity(identity);
3863 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003864 }
3865
3866 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3867 int uid, RemoteCallback callback) {
3868 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3869 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3870 @Override
3871 public void onResult(Bundle value) throws RemoteException {
3872 handleAuthenticatorResponse(true);
3873 }
3874
3875 @Override
3876 public void onRequestContinued() {
3877 /* ignore */
3878 }
3879
3880 @Override
3881 public void onError(int errorCode, String errorMessage) throws RemoteException {
3882 handleAuthenticatorResponse(false);
3883 }
3884
3885 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3886 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003887 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003888 UserHandle.getUserHandleForUid(uid));
3889 if (callback != null) {
3890 Bundle result = new Bundle();
3891 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3892 callback.sendResult(result);
3893 }
3894 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003895 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003896 }
3897
3898 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003899 public boolean someUserHasAccount(@NonNull final Account account) {
3900 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3901 throw new SecurityException("Only system can check for accounts across users");
3902 }
3903 final long token = Binder.clearCallingIdentity();
3904 try {
3905 AccountAndUser[] allAccounts = getAllAccounts();
3906 for (int i = allAccounts.length - 1; i >= 0; i--) {
3907 if (allAccounts[i].account.equals(account)) {
3908 return true;
3909 }
3910 }
3911 return false;
3912 } finally {
3913 Binder.restoreCallingIdentity(token);
3914 }
3915 }
3916
Fred Quintana33269202009-04-20 16:05:10 -07003917 private class GetAccountsByTypeAndFeatureSession extends Session {
3918 private final String[] mFeatures;
3919 private volatile Account[] mAccountsOfType = null;
3920 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3921 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003922 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003923 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003924
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003925 public GetAccountsByTypeAndFeatureSession(
3926 UserAccounts accounts,
3927 IAccountManagerResponse response,
3928 String type,
3929 String[] features,
3930 int callingUid,
3931 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003932 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003933 true /* stripAuthTokenFromResult */, null /* accountName */,
3934 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003935 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003936 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003937 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003938 }
3939
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003940 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003941 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07003942 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
3943 mCallingUid, mPackageName, false /* include managed not visible*/);
Fred Quintana33269202009-04-20 16:05:10 -07003944 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003945 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003946 mCurrentAccount = 0;
3947
3948 checkAccount();
3949 }
3950
3951 public void checkAccount() {
3952 if (mCurrentAccount >= mAccountsOfType.length) {
3953 sendResult();
3954 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003955 }
Fred Quintana33269202009-04-20 16:05:10 -07003956
Fred Quintana29e94b82010-03-10 12:11:51 -08003957 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3958 if (accountAuthenticator == null) {
3959 // It is possible that the authenticator has died, which is indicated by
3960 // mAuthenticator being set to null. If this happens then just abort.
3961 // There is no need to send back a result or error in this case since
3962 // that already happened when mAuthenticator was cleared.
3963 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3964 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3965 + " connected to the authenticator, " + toDebugString());
3966 }
3967 return;
3968 }
Fred Quintana33269202009-04-20 16:05:10 -07003969 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003970 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003971 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003972 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003973 }
3974 }
3975
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003976 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003977 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003978 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003979 mNumResults++;
3980 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003981 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003982 return;
3983 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003984 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003985 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3986 }
3987 mCurrentAccount++;
3988 checkAccount();
3989 }
3990
3991 public void sendResult() {
3992 IAccountManagerResponse response = getResponseAndClose();
3993 if (response != null) {
3994 try {
3995 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3996 for (int i = 0; i < accounts.length; i++) {
3997 accounts[i] = mAccountsWithFeatures.get(i);
3998 }
Fred Quintana56285a62010-12-02 14:20:51 -08003999 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4000 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4001 + response);
4002 }
Fred Quintana33269202009-04-20 16:05:10 -07004003 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004004 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004005 response.onResult(result);
4006 } catch (RemoteException e) {
4007 // if the caller is dead then there is no one to care about remote exceptions
4008 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4009 Log.v(TAG, "failure while notifying response", e);
4010 }
4011 }
4012 }
4013 }
4014
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004015 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004016 protected String toDebugString(long now) {
4017 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4018 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4019 }
4020 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004021
Amith Yamasani04e0d262012-02-14 11:50:53 -08004022 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004023 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004024 * @hide
4025 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004026 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004027 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004028 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004029 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004030 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4031 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004032 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004033 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004034 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004035 long identityToken = clearCallingIdentity();
4036 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004037 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004038 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004039 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004040 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004041 opPackageName,
4042 visibleAccountTypes,
4043 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004044 } finally {
4045 restoreCallingIdentity(identityToken);
4046 }
4047 }
4048
Amith Yamasanif29f2362012-04-05 18:29:52 -07004049 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004050 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004051 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004052 * @hide
4053 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004054 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004055 public AccountAndUser[] getRunningAccounts() {
4056 final int[] runningUserIds;
4057 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004058 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004059 } catch (RemoteException e) {
4060 // Running in system_server; should never happen
4061 throw new RuntimeException(e);
4062 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004063 return getAccounts(runningUserIds);
4064 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004065
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004066 /**
4067 * Returns accounts for all users, ignores visibility values.
4068 *
4069 * @hide
4070 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004071 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004072 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004073 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004074 final int[] userIds = new int[users.size()];
4075 for (int i = 0; i < userIds.length; i++) {
4076 userIds[i] = users.get(i).id;
4077 }
4078 return getAccounts(userIds);
4079 }
4080
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004081 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004082 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004083 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004084 for (int userId : userIds) {
4085 UserAccounts userAccounts = getUserAccounts(userId);
4086 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004087 Account[] accounts = getAccountsFromCache(
4088 userAccounts,
4089 null /* type */,
4090 Binder.getCallingUid(),
4091 null /* packageName */,
4092 false /* include managed not visible*/);
4093 for (Account account : accounts) {
4094 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004095 }
4096 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004097
4098 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4099 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004100 }
4101
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004102 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004103 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004104 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004105 int callingUid = Binder.getCallingUid();
4106 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004107 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004108 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004109 }
4110
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004111 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004112 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004113 String type,
4114 int userId,
4115 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004116 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004117 String opPackageName,
4118 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004119 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004120 // Only allow the system process to read accounts of other users
4121 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004122 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004123 && mContext.checkCallingOrSelfPermission(
4124 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4125 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004126 throw new SecurityException("User " + UserHandle.getCallingUserId()
4127 + " trying to get account for " + userId);
4128 }
4129
Fred Quintana56285a62010-12-02 14:20:51 -08004130 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4131 Log.v(TAG, "getAccounts: accountType " + type
4132 + ", caller's uid " + Binder.getCallingUid()
4133 + ", pid " + Binder.getCallingPid());
4134 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004135
4136 // If the original calling app was using account choosing activity
4137 // provided by the framework or authenticator we'll passing in
4138 // the original caller's uid here, which is what should be used for filtering.
4139 List<String> managedTypes =
4140 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4141 if (packageUid != -1 &&
4142 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4143 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004144 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004145 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004146 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004147 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4148 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004149 if (visibleAccountTypes.isEmpty()
4150 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004151 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004152 } else if (visibleAccountTypes.contains(type)) {
4153 // Prune the list down to just the requested type.
4154 visibleAccountTypes = new ArrayList<>();
4155 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004156 } // else aggregate all the visible accounts (it won't matter if the
4157 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004158
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004159 long identityToken = clearCallingIdentity();
4160 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004161 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004162 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004163 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004164 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004165 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004166 visibleAccountTypes,
4167 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004168 } finally {
4169 restoreCallingIdentity(identityToken);
4170 }
4171 }
4172
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004173 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004174 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004175 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004176 int callingUid,
4177 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004178 List<String> visibleAccountTypes,
4179 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004180 ArrayList<Account> visibleAccounts = new ArrayList<>();
4181 for (String visibleType : visibleAccountTypes) {
4182 Account[] accountsForType = getAccountsFromCache(
4183 userAccounts, visibleType, callingUid, callingPackage,
4184 includeUserManagedNotVisible);
4185 if (accountsForType != null) {
4186 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004187 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004188 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004189 Account[] result = new Account[visibleAccounts.size()];
4190 for (int i = 0; i < visibleAccounts.size(); i++) {
4191 result[i] = visibleAccounts.get(i);
4192 }
4193 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004194 }
4195
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004196 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004197 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4198 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004199 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004200 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004201 for (Account account : accounts) {
4202 addSharedAccountAsUser(account, userId);
4203 }
4204 }
4205
4206 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004207 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004208 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004209 accounts.accountsDb.deleteSharedAccount(account);
4210 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004211 if (accountId < 0) {
4212 Log.w(TAG, "insertAccountIntoDatabase: " + account
4213 + ", skipping the DB insert failed");
4214 return false;
4215 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004216 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4217 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004218 return true;
4219 }
4220
4221 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004222 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4223 userId = handleIncomingUser(userId);
4224 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004225 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4226 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004227 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004228 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004229 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004230 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004231 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004232 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004233 }
4234 return r > 0;
4235 }
4236
4237 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004238 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004239 return removeSharedAccountAsUser(account, userId, getCallingUid());
4240 }
4241
4242 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004243 userId = handleIncomingUser(userId);
4244 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004245 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4246 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004247 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004248 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004249 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004250 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004251 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004252 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004253 }
4254
4255 @Override
4256 public Account[] getSharedAccountsAsUser(int userId) {
4257 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004258 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004259 synchronized (accounts.dbLock) {
4260 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4261 Account[] accountArray = new Account[accountList.size()];
4262 accountList.toArray(accountArray);
4263 return accountArray;
4264 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004265 }
4266
4267 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004268 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004269 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004270 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004271 }
4272
Amith Yamasani27db4682013-03-30 17:07:47 -07004273 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004274 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004275 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004276 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004277 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004278 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004279 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4280 + callingUid + " with uid=" + uid);
4281 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004282 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004283 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004284 }
4285
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004286 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004287 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004288 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4289 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004290 int callingUid = Binder.getCallingUid();
4291 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004292 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004293 int packageUid = -1;
4294 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004295 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4296 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004297 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004298 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004299 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004300 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004301 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4302 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004303 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004304 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004305 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004306 }
4307
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004308 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004309 public void getAccountsByFeatures(
4310 IAccountManagerResponse response,
4311 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004312 String[] features,
4313 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004314 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004315 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004316 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4317 Log.v(TAG, "getAccounts: accountType " + type
4318 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004319 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004320 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004321 + ", pid " + Binder.getCallingPid());
4322 }
Fred Quintana382601f2010-03-25 12:25:10 -07004323 if (response == null) throw new IllegalArgumentException("response is null");
4324 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004325 int userId = UserHandle.getCallingUserId();
4326
Svetoslavf3f02ac2015-09-08 14:36:35 -07004327 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4328 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004329 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004330 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004331 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004332 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004333 try {
4334 response.onResult(result);
4335 } catch (RemoteException e) {
4336 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4337 }
4338 return;
4339 }
Fred Quintana33269202009-04-20 16:05:10 -07004340 long identityToken = clearCallingIdentity();
4341 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004342 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004343 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004344 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4345 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004346 Bundle result = new Bundle();
4347 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4348 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004349 return;
4350 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004351 new GetAccountsByTypeAndFeatureSession(
4352 userAccounts,
4353 response,
4354 type,
4355 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004356 callingUid,
4357 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004358 } finally {
4359 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004360 }
4361 }
4362
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004363 @Override
4364 public void onAccountAccessed(String token) throws RemoteException {
4365 final int uid = Binder.getCallingUid();
4366 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4367 return;
4368 }
4369 final int userId = UserHandle.getCallingUserId();
4370 final long identity = Binder.clearCallingIdentity();
4371 try {
4372 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4373 if (Objects.equals(account.getAccessId(), token)) {
4374 // An app just accessed the account. At this point it knows about
4375 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004376 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004377 if (!hasAccountAccess(account, null, uid)) {
4378 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4379 uid, true);
4380 }
4381 }
4382 }
4383 } finally {
4384 Binder.restoreCallingIdentity(identity);
4385 }
4386 }
4387
Fred Quintanaa698f422009-04-08 19:14:54 -07004388 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004389 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004390 IAccountManagerResponse mResponse;
4391 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004392 final boolean mExpectActivityLaunch;
4393 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004394 final String mAccountName;
4395 // Indicates if we need to add auth details(like last credential time)
4396 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004397 // If set, we need to update the last authenticated time. This is
4398 // currently
4399 // used on
4400 // successful confirming credentials.
4401 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004402
Fred Quintana33269202009-04-20 16:05:10 -07004403 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004404 private int mNumRequestContinued = 0;
4405 private int mNumErrors = 0;
4406
Fred Quintana60307342009-03-24 22:48:12 -07004407 IAccountAuthenticator mAuthenticator = null;
4408
Fred Quintana8570f742010-02-18 10:32:54 -08004409 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004410 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004411
Amith Yamasani04e0d262012-02-14 11:50:53 -08004412 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004413 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4414 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004415 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4416 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4417 }
4418
4419 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4420 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4421 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004422 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004423 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004424 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004425 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004426 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004427 mResponse = response;
4428 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004429 mExpectActivityLaunch = expectActivityLaunch;
4430 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004431 mAccountName = accountName;
4432 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004433 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004434
Fred Quintanaa698f422009-04-08 19:14:54 -07004435 synchronized (mSessions) {
4436 mSessions.put(toString(), this);
4437 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004438 if (response != null) {
4439 try {
4440 response.asBinder().linkToDeath(this, 0 /* flags */);
4441 } catch (RemoteException e) {
4442 mResponse = null;
4443 binderDied();
4444 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004445 }
Fred Quintana60307342009-03-24 22:48:12 -07004446 }
4447
Fred Quintanaa698f422009-04-08 19:14:54 -07004448 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004449 if (mResponse == null) {
4450 // this session has already been closed
4451 return null;
4452 }
Fred Quintana60307342009-03-24 22:48:12 -07004453 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004454 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004455 return response;
4456 }
4457
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004458 /**
4459 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4460 * security policy.
4461 *
4462 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004463 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004464 * supplied entries in the system Settings app.
4465 */
4466 protected void checkKeyIntent(
4467 int authUid,
4468 Intent intent) throws SecurityException {
4469 long bid = Binder.clearCallingIdentity();
4470 try {
4471 PackageManager pm = mContext.getPackageManager();
4472 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4473 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4474 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004475 if (!isExportedSystemActivity(targetActivityInfo)
4476 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4477 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004478 String pkgName = targetActivityInfo.packageName;
4479 String activityName = targetActivityInfo.name;
4480 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4481 + "does not share a signature with the supplying authenticator (%s).";
4482 throw new SecurityException(
4483 String.format(tmpl, activityName, pkgName, mAccountType));
4484 }
4485 } finally {
4486 Binder.restoreCallingIdentity(bid);
4487 }
4488 }
4489
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004490 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4491 String className = activityInfo.name;
4492 return "android".equals(activityInfo.packageName) &&
4493 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4494 || CantAddAccountActivity.class.getName().equals(className));
4495 }
4496
Fred Quintanaa698f422009-04-08 19:14:54 -07004497 private void close() {
4498 synchronized (mSessions) {
4499 if (mSessions.remove(toString()) == null) {
4500 // the session was already closed, so bail out now
4501 return;
4502 }
4503 }
4504 if (mResponse != null) {
4505 // stop listening for response deaths
4506 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4507
4508 // clear this so that we don't accidentally send any further results
4509 mResponse = null;
4510 }
4511 cancelTimeout();
4512 unbind();
4513 }
4514
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004515 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004516 public void binderDied() {
4517 mResponse = null;
4518 close();
4519 }
4520
4521 protected String toDebugString() {
4522 return toDebugString(SystemClock.elapsedRealtime());
4523 }
4524
4525 protected String toDebugString(long now) {
4526 return "Session: expectLaunch " + mExpectActivityLaunch
4527 + ", connected " + (mAuthenticator != null)
4528 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4529 + "/" + mNumErrors + ")"
4530 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4531 }
4532
Fred Quintana60307342009-03-24 22:48:12 -07004533 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004534 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4535 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4536 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004537 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004538 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004539 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004540 }
4541 }
4542
4543 private void unbind() {
4544 if (mAuthenticator != null) {
4545 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004546 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004547 }
4548 }
4549
Fred Quintana60307342009-03-24 22:48:12 -07004550 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004551 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004552 }
4553
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004554 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004555 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004556 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004557 try {
4558 run();
4559 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004560 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004561 "remote exception");
4562 }
Fred Quintana60307342009-03-24 22:48:12 -07004563 }
4564
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004565 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004566 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004567 mAuthenticator = null;
4568 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004569 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004570 try {
4571 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4572 "disconnected");
4573 } catch (RemoteException e) {
4574 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4575 Log.v(TAG, "Session.onServiceDisconnected: "
4576 + "caught RemoteException while responding", e);
4577 }
4578 }
Fred Quintana60307342009-03-24 22:48:12 -07004579 }
4580 }
4581
Fred Quintanab839afc2009-10-14 15:57:28 -07004582 public abstract void run() throws RemoteException;
4583
Fred Quintana60307342009-03-24 22:48:12 -07004584 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004585 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004586 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004587 try {
4588 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4589 "timeout");
4590 } catch (RemoteException e) {
4591 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4592 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4593 e);
4594 }
4595 }
Fred Quintana60307342009-03-24 22:48:12 -07004596 }
4597 }
4598
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004599 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004600 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004601 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004602 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004603 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004604 if (result != null) {
4605 boolean isSuccessfulConfirmCreds = result.getBoolean(
4606 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004607 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004608 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4609 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004610 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004611 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4612 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004613 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004614 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004615 if (needUpdate || mAuthDetailsRequired) {
4616 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4617 if (needUpdate && accountPresent) {
4618 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4619 }
4620 if (mAuthDetailsRequired) {
4621 long lastAuthenticatedTime = -1;
4622 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004623 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004624 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004625 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004626 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004627 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004628 lastAuthenticatedTime);
4629 }
4630 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004631 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004632 if (result != null
4633 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004634 checkKeyIntent(
4635 Binder.getCallingUid(),
4636 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004637 }
4638 if (result != null
4639 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004640 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4641 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004642 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4643 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004644 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4645 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004646 }
Fred Quintana60307342009-03-24 22:48:12 -07004647 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004648 IAccountManagerResponse response;
4649 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004650 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004651 response = mResponse;
4652 } else {
4653 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004654 }
Fred Quintana60307342009-03-24 22:48:12 -07004655 if (response != null) {
4656 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004657 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004658 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4659 Log.v(TAG, getClass().getSimpleName()
4660 + " calling onError() on response " + response);
4661 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004662 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004663 "null bundle returned");
4664 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004665 if (mStripAuthTokenFromResult) {
4666 result.remove(AccountManager.KEY_AUTHTOKEN);
4667 }
Fred Quintana56285a62010-12-02 14:20:51 -08004668 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4669 Log.v(TAG, getClass().getSimpleName()
4670 + " calling onResult() on response " + response);
4671 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004672 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4673 (intent == null)) {
4674 // All AccountManager error codes are greater than 0
4675 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4676 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4677 } else {
4678 response.onResult(result);
4679 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004680 }
Fred Quintana60307342009-03-24 22:48:12 -07004681 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004682 // if the caller is dead then there is no one to care about remote exceptions
4683 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4684 Log.v(TAG, "failure while notifying response", e);
4685 }
Fred Quintana60307342009-03-24 22:48:12 -07004686 }
4687 }
4688 }
Fred Quintana60307342009-03-24 22:48:12 -07004689
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004690 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004691 public void onRequestContinued() {
4692 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004693 }
4694
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004695 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004696 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004697 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004698 IAccountManagerResponse response = getResponseAndClose();
4699 if (response != null) {
4700 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004701 Log.v(TAG, getClass().getSimpleName()
4702 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004703 }
4704 try {
4705 response.onError(errorCode, errorMessage);
4706 } catch (RemoteException e) {
4707 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4708 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4709 }
4710 }
4711 } else {
4712 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4713 Log.v(TAG, "Session.onError: already closed");
4714 }
Fred Quintana60307342009-03-24 22:48:12 -07004715 }
4716 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004717
4718 /**
4719 * find the component name for the authenticator and initiate a bind
4720 * if no authenticator or the bind fails then return false, otherwise return true
4721 */
4722 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004723 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4724 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4725 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004726 if (authenticatorInfo == null) {
4727 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4728 Log.v(TAG, "there is no authenticator for " + authenticatorType
4729 + ", bailing out");
4730 }
4731 return false;
4732 }
4733
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004734 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004735 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004736 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4737 + " which isn't encryption aware");
4738 return false;
4739 }
4740
Fred Quintanab839afc2009-10-14 15:57:28 -07004741 Intent intent = new Intent();
4742 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4743 intent.setComponent(authenticatorInfo.componentName);
4744 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4745 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4746 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004747 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004748 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004749 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4750 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4751 }
4752 return false;
4753 }
4754
Fred Quintanab839afc2009-10-14 15:57:28 -07004755 return true;
4756 }
Fred Quintana60307342009-03-24 22:48:12 -07004757 }
4758
Svet Ganov5d09c992016-09-07 09:57:41 -07004759 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004760 MessageHandler(Looper looper) {
4761 super(looper);
4762 }
Costin Manolache3348f142009-09-29 18:58:36 -07004763
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004764 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004765 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004766 switch (msg.what) {
4767 case MESSAGE_TIMED_OUT:
4768 Session session = (Session)msg.obj;
4769 session.onTimedOut();
4770 break;
4771
Amith Yamasani5be347b2013-03-31 17:44:31 -07004772 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004773 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004774 break;
4775
Fred Quintana60307342009-03-24 22:48:12 -07004776 default:
4777 throw new IllegalStateException("unhandled message: " + msg.what);
4778 }
4779 }
4780 }
4781
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004782 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004783 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004784 }
4785
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004786 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004787 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004788 }
4789
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004790 /*
4791 * This function receives an opened writable database.
4792 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004793 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004794 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004795 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004796 }
4797
4798 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004799 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004800 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004801 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004802 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004803
4804 class LogRecordTask implements Runnable {
4805 private final String action;
4806 private final String tableName;
4807 private final long accountId;
4808 private final UserAccounts userAccount;
4809 private final int callingUid;
4810 private final long userDebugDbInsertionPoint;
4811
4812 LogRecordTask(final String action,
4813 final String tableName,
4814 final long accountId,
4815 final UserAccounts userAccount,
4816 final int callingUid,
4817 final long userDebugDbInsertionPoint) {
4818 this.action = action;
4819 this.tableName = tableName;
4820 this.accountId = accountId;
4821 this.userAccount = userAccount;
4822 this.callingUid = callingUid;
4823 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4824 }
4825
4826 public void run() {
4827 SQLiteStatement logStatement = userAccount.statementForLogging;
4828 logStatement.bindLong(1, accountId);
4829 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004830 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004831 logStatement.bindLong(4, callingUid);
4832 logStatement.bindString(5, tableName);
4833 logStatement.bindLong(6, userDebugDbInsertionPoint);
4834 logStatement.execute();
4835 logStatement.clearBindings();
4836 }
4837 }
4838
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004839 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4840 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004841 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004842 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004843 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004844 }
4845
4846 /*
4847 * This should only be called once to compile the sql statement for logging
4848 * and to find the insertion point.
4849 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004850 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4851 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4852 .calculateDebugTableInsertionPoint();
4853 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004854 }
4855
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004856 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004857 return asBinder();
4858 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004859
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004860 /**
4861 * Searches array of arguments for the specified string
4862 * @param args array of argument strings
4863 * @param value value to search for
4864 * @return true if the value is contained in the array
4865 */
4866 private static boolean scanArgs(String[] args, String value) {
4867 if (args != null) {
4868 for (String arg : args) {
4869 if (value.equals(arg)) {
4870 return true;
4871 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004872 }
4873 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004874 return false;
4875 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004876
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004877 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004878 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Kenny Root3abd75b2011-09-29 11:00:41 -07004879 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4880 != PackageManager.PERMISSION_GRANTED) {
4881 fout.println("Permission Denial: can't dump AccountsManager from from pid="
4882 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
4883 + " without permission " + android.Manifest.permission.DUMP);
4884 return;
4885 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004886 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004887 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004888
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004889 final List<UserInfo> users = getUserManager().getUsers();
4890 for (UserInfo user : users) {
4891 ipw.println("User " + user + ":");
4892 ipw.increaseIndent();
4893 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4894 ipw.println();
4895 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004896 }
4897 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004898
Amith Yamasani04e0d262012-02-14 11:50:53 -08004899 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4900 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004901 if (isCheckinRequest) {
4902 // This is a checkin request. *Only* upload the account types and the count of
4903 // each.
4904 synchronized (userAccounts.dbLock) {
4905 userAccounts.accountsDb.dumpDeAccountsTable(fout);
4906 }
4907 } else {
4908 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
4909 Process.SYSTEM_UID, null /* packageName */, false);
4910 fout.println("Accounts: " + accounts.length);
4911 for (Account account : accounts) {
4912 fout.println(" " + account);
4913 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004914
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004915 // Add debug information.
4916 fout.println();
4917 synchronized (userAccounts.dbLock) {
4918 userAccounts.accountsDb.dumpDebugTable(fout);
4919 }
4920 fout.println();
4921 synchronized (mSessions) {
4922 final long now = SystemClock.elapsedRealtime();
4923 fout.println("Active Sessions: " + mSessions.size());
4924 for (Session session : mSessions.values()) {
4925 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07004926 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004927 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004928
4929 fout.println();
4930 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004931 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004932 }
4933
Amith Yamasani04e0d262012-02-14 11:50:53 -08004934 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004935 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004936 long identityToken = clearCallingIdentity();
4937 try {
4938 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4939 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4940 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004941
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004942 if (intent.getComponent() != null &&
4943 GrantCredentialsPermissionActivity.class.getName().equals(
4944 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004945 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004946 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004947 Context contextForUser = getContextForUser(new UserHandle(userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004948 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07004949 intent.addCategory(String.valueOf(notificationId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004950
Fred Quintana33f889a2009-09-14 17:31:26 -07004951 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004952 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004953 Notification n =
4954 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004955 .setWhen(0)
4956 .setSmallIcon(android.R.drawable.stat_sys_warning)
4957 .setColor(contextForUser.getColor(
4958 com.android.internal.R.color.system_notification_accent_color))
4959 .setContentTitle(String.format(notificationTitleFormat, account.name))
4960 .setContentText(message)
4961 .setContentIntent(PendingIntent.getActivityAsUser(
4962 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004963 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004964 .build();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004965 installNotification(notificationId, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004966 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004967 } finally {
4968 restoreCallingIdentity(identityToken);
4969 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004970 }
4971
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004972 private void installNotification(int notificationId, final Notification notification,
4973 String packageName, int userId) {
4974 final long token = clearCallingIdentity();
4975 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004976 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004977 try {
4978 notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
4979 notificationId, notification, new int[1], userId);
4980 } catch (RemoteException e) {
4981 /* ignore - local call */
4982 }
4983 } finally {
4984 Binder.restoreCallingIdentity(token);
4985 }
Fred Quintana56285a62010-12-02 14:20:51 -08004986 }
4987
Fyodor Kupolovda993802016-09-21 14:47:10 -07004988 private void cancelNotification(int id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004989 cancelNotification(id, mContext.getPackageName(), user);
4990 }
4991
Fyodor Kupolovda993802016-09-21 14:47:10 -07004992 private void cancelNotification(int id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004993 long identityToken = clearCallingIdentity();
4994 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004995 INotificationManager service = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004996 service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
4997 } catch (RemoteException e) {
4998 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004999 } finally {
5000 restoreCallingIdentity(identityToken);
5001 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005002 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005003
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005004 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
5005 final long identity = Binder.clearCallingIdentity();
5006 try {
5007 IPackageManager pm = ActivityThread.getPackageManager();
5008 for (String perm : permissions) {
5009 if (pm.checkPermission(perm, packageName, userId)
5010 == PackageManager.PERMISSION_GRANTED) {
5011 return true;
5012 }
5013 }
5014 } catch (RemoteException e) {
5015 /* ignore - local call */
5016 } finally {
5017 Binder.restoreCallingIdentity(identity);
5018 }
5019 return false;
5020 }
5021
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005022 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5023 for (String perm : permissions) {
5024 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5025 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5026 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5027 }
5028 final int opCode = AppOpsManager.permissionToOpCode(perm);
5029 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5030 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5031 return true;
5032 }
5033 }
5034 }
5035 return false;
5036 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005037
Amith Yamasani67df64b2012-12-14 12:09:36 -08005038 private int handleIncomingUser(int userId) {
5039 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005040 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005041 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5042 } catch (RemoteException re) {
5043 // Shouldn't happen, local.
5044 }
5045 return userId;
5046 }
5047
Christopher Tateccbf84f2013-05-08 15:25:41 -07005048 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005049 String[] packages;
5050 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005051 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005052 packages = mPackageManager.getPackagesForUid(callingUid);
5053 } finally {
5054 Binder.restoreCallingIdentity(identityToken);
5055 }
5056 if (packages == null) {
5057 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005058 return false;
5059 }
Fred Quintana7be59642009-08-24 18:29:25 -07005060 for (String name : packages) {
5061 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005062 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08005063 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08005064 && (packageInfo.applicationInfo.privateFlags
5065 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07005066 return true;
5067 }
5068 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005069 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07005070 return false;
5071 }
5072 }
5073 return false;
5074 }
5075
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005076 private boolean permissionIsGranted(
5077 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005078 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5079 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5080 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5081 }
5082 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005083 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005084
5085 if (isPrivileged(callerUid)) {
5086 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5087 Log.v(TAG, "Access to " + account + " granted calling uid "
5088 + callerUid + " privileged");
5089 }
5090 return true;
5091 }
5092 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5093 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5094 Log.v(TAG, "Access to " + account + " granted calling uid "
5095 + callerUid + " manages the account");
5096 }
5097 return true;
5098 }
5099 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5100 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5101 Log.v(TAG, "Access to " + account + " granted calling uid "
5102 + callerUid + " user granted access");
5103 }
5104 return true;
5105 }
5106
5107 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5108 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5109 }
5110
5111 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005112 }
5113
Svetoslavf3f02ac2015-09-08 14:36:35 -07005114 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5115 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005116 if (accountType == null) {
5117 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005118 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005119 return getTypesVisibleToCaller(callingUid, userId,
5120 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005121 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005122 }
5123
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005124 // Method checks visibility for applications targeing API level below {@link
5125 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005126 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005127 private boolean checkGetAccountsPermission(String packageName, int userId) {
5128 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5129 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5130 }
5131
5132 private boolean checkReadContactsPermission(String packageName, int userId) {
5133 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5134 }
5135
5136 /**
5137 * Method checks package uid and signature with Authenticator which manages accountType.
5138 *
5139 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5140 * SIGNATURE_CHECK_MISMATCH otherwise.
5141 */
5142 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5143 if (accountType == null) {
5144 return SIGNATURE_CHECK_MISMATCH;
5145 }
5146
5147 long identityToken = Binder.clearCallingIdentity();
5148 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5149 try {
5150 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5151 } finally {
5152 Binder.restoreCallingIdentity(identityToken);
5153 }
5154 // Check for signature match with Authenticator.
5155 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5156 : serviceInfos) {
5157 if (accountType.equals(serviceInfo.type.type)) {
5158 if (serviceInfo.uid == callingUid) {
5159 return SIGNATURE_CHECK_UID_MATCH;
5160 }
5161 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5162 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5163 return SIGNATURE_CHECK_MATCH;
5164 }
5165 }
5166 }
5167 return SIGNATURE_CHECK_MISMATCH;
5168 }
5169
5170 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005171 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5172 if (accountType == null) {
5173 return false;
5174 } else {
5175 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5176 }
5177 }
5178
Svetoslavf3f02ac2015-09-08 14:36:35 -07005179 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5180 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005181 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005182 }
5183
5184 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005185 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005186 }
5187
5188 private List<String> getTypesForCaller(
5189 int callingUid, int userId, boolean isOtherwisePermitted) {
5190 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005191 long identityToken = Binder.clearCallingIdentity();
5192 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5193 try {
5194 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5195 } finally {
5196 Binder.restoreCallingIdentity(identityToken);
5197 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005198 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005199 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005200 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5201 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005202 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005203 }
5204 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005205 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005206 }
5207
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005208 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5209 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5210 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5211 if (account.name.equals(accountName)) {
5212 return true;
5213 }
5214 }
5215 }
5216 return false;
5217 }
5218
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005219 private static void checkManageUsersPermission(String message) {
5220 if (ActivityManager.checkComponentPermission(
5221 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5222 != PackageManager.PERMISSION_GRANTED) {
5223 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5224 }
5225 }
5226
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005227 private static void checkManageOrCreateUsersPermission(String message) {
5228 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5229 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5230 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5231 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5232 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5233 + message);
5234 }
5235 }
5236
Amith Yamasani04e0d262012-02-14 11:50:53 -08005237 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5238 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005239 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005240 return true;
5241 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005242 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005243 synchronized (accounts.dbLock) {
5244 synchronized (accounts.cacheLock) {
5245 long grantsCount;
5246 if (authTokenType != null) {
5247 grantsCount = accounts.accountsDb
5248 .findMatchingGrantsCount(callerUid, authTokenType, account);
5249 } else {
5250 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5251 account);
5252 }
5253 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005254
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005255 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5256 // TODO: Skip this check when running automated tests. Replace this
5257 // with a more general solution.
5258 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5259 + authTokenType + " by uid " + callerUid
5260 + " but ignoring since device is in test harness.");
5261 return true;
5262 }
5263 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005264 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005265 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005266 }
5267
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005268 private boolean isSystemUid(int callingUid) {
5269 String[] packages = null;
5270 long ident = Binder.clearCallingIdentity();
5271 try {
5272 packages = mPackageManager.getPackagesForUid(callingUid);
5273 } finally {
5274 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005275 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005276 if (packages != null) {
5277 for (String name : packages) {
5278 try {
5279 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5280 if (packageInfo != null
5281 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5282 != 0) {
5283 return true;
5284 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005285 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005286 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5287 }
5288 }
5289 } else {
5290 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005291 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005292 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005293 }
5294
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005295 /** Succeeds if any of the specified permissions are granted. */
5296 private void checkReadAccountsPermitted(
5297 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005298 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005299 int userId,
5300 String opPackageName) {
5301 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005302 String msg = String.format(
5303 "caller uid %s cannot access %s accounts",
5304 callingUid,
5305 accountType);
5306 Log.w(TAG, " " + msg);
5307 throw new SecurityException(msg);
5308 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005309 }
5310
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005311 private boolean canUserModifyAccounts(int userId, int callingUid) {
5312 // the managing app can always modify accounts
5313 if (isProfileOwner(callingUid)) {
5314 return true;
5315 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005316 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5317 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5318 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005319 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005320 return true;
5321 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005322
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005323 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5324 // the managing app can always modify accounts
5325 if (isProfileOwner(callingUid)) {
5326 return true;
5327 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005328 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5329 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005330 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005331 if (typesArray == null) {
5332 return true;
5333 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005334 for (String forbiddenType : typesArray) {
5335 if (forbiddenType.equals(accountType)) {
5336 return false;
5337 }
5338 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005339 return true;
5340 }
5341
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005342 private boolean isProfileOwner(int uid) {
5343 final DevicePolicyManagerInternal dpmi =
5344 LocalServices.getService(DevicePolicyManagerInternal.class);
5345 return (dpmi != null)
5346 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5347 }
5348
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005349 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005350 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5351 throws RemoteException {
5352 final int callingUid = getCallingUid();
5353
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005354 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005355 throw new SecurityException();
5356 }
5357
5358 if (value) {
5359 grantAppPermission(account, authTokenType, uid);
5360 } else {
5361 revokeAppPermission(account, authTokenType, uid);
5362 }
5363 }
5364
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005365 /**
5366 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5367 * <p>
5368 * Although this is public it can only be accessed via the AccountManagerService object
5369 * which is in the system. This means we don't need to protect it with permissions.
5370 * @hide
5371 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005372 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005373 if (account == null || authTokenType == null) {
5374 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005375 return;
5376 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005377 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005378 synchronized (accounts.dbLock) {
5379 synchronized (accounts.cacheLock) {
5380 long accountId = accounts.accountsDb.findDeAccountId(account);
5381 if (accountId >= 0) {
5382 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5383 }
5384 cancelNotification(
5385 getCredentialPermissionNotificationId(account, authTokenType, uid),
5386 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005387
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005388 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5389 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005390 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005391
5392 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5393 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5394 : mAppPermissionChangeListeners) {
5395 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5396 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005397 }
5398
5399 /**
5400 * Don't allow callers with the given uid permission to get credentials for
5401 * account/authTokenType.
5402 * <p>
5403 * Although this is public it can only be accessed via the AccountManagerService object
5404 * which is in the system. This means we don't need to protect it with permissions.
5405 * @hide
5406 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005407 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005408 if (account == null || authTokenType == null) {
5409 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005410 return;
5411 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005412 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005413 synchronized (accounts.dbLock) {
5414 synchronized (accounts.cacheLock) {
5415 accounts.accountsDb.beginTransaction();
5416 try {
5417 long accountId = accounts.accountsDb.findDeAccountId(account);
5418 if (accountId >= 0) {
5419 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5420 accountId, authTokenType, uid);
5421 accounts.accountsDb.setTransactionSuccessful();
5422 }
5423 } finally {
5424 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005425 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005426
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005427 cancelNotification(
5428 getCredentialPermissionNotificationId(account, authTokenType, uid),
5429 UserHandle.of(accounts.userId));
5430 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005431 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005432
5433 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5434 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5435 : mAppPermissionChangeListeners) {
5436 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5437 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005438 }
Fred Quintana56285a62010-12-02 14:20:51 -08005439
Amith Yamasani04e0d262012-02-14 11:50:53 -08005440 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5441 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005442 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005443 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005444 for (Account curAccount : oldAccountsForType) {
5445 if (!curAccount.equals(account)) {
5446 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005447 }
5448 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005449 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005450 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005451 } else {
5452 Account[] newAccountsForType = new Account[newAccountsList.size()];
5453 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005454 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005455 }
Fred Quintana56285a62010-12-02 14:20:51 -08005456 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005457 accounts.userDataCache.remove(account);
5458 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005459 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005460 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005461 }
5462
5463 /**
5464 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005465 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5466 * processes and if you will return this account to apps you should return the result.
5467 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005468 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005469 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005470 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005471 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5472 Account[] newAccountsForType = new Account[oldLength + 1];
5473 if (accountsForType != null) {
5474 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005475 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005476 String token = account.getAccessId() != null ? account.getAccessId()
5477 : UUID.randomUUID().toString();
5478 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005479 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005480 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005481 }
5482
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005483 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005484 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005485 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005486 String visibilityFilterPackage = callingPackage;
5487 if (visibilityFilterPackage == null) {
5488 visibilityFilterPackage = getPackageNameForUid(callingUid);
5489 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005490 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005491 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005492 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005493 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5494 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5495 || (includeManagedNotVisible
5496 && (visibility
5497 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5498 firstPass.put(account, visibility);
5499 }
5500 }
5501 Map<Account, Integer> secondPass =
5502 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5503
5504 Account[] filtered = new Account[secondPass.size()];
5505 filtered = secondPass.keySet().toArray(filtered);
5506 return filtered;
5507 }
5508
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005509 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005510 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005511 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005512 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005513 // first part is to filter shared accounts.
5514 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005515 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005516 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005517 return unfiltered;
5518 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005519 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005520 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005521 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005522 if (packages == null) {
5523 packages = new String[] {};
5524 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005525 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005526 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005527 // This might be a temporary way to specify a visible list
5528 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005529 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5530 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005531 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005532 return unfiltered;
5533 }
5534 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005535 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005536 if (ArrayUtils.isEmpty(sharedAccounts)) {
5537 return unfiltered;
5538 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005539 String requiredAccountType = "";
5540 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005541 // If there's an explicit callingPackage specified, check if that package
5542 // opted in to see restricted accounts.
5543 if (callingPackage != null) {
5544 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005545 if (pi != null && pi.restrictedAccountType != null) {
5546 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005547 }
5548 } else {
5549 // Otherwise check if the callingUid has a package that has opted in
5550 for (String packageName : packages) {
5551 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5552 if (pi != null && pi.restrictedAccountType != null) {
5553 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005554 break;
5555 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005556 }
5557 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005558 } catch (NameNotFoundException e) {
5559 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005560 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005561 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005562 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5563 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005564 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005565 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005566 } else {
5567 boolean found = false;
5568 for (Account shared : sharedAccounts) {
5569 if (shared.equals(account)) {
5570 found = true;
5571 break;
5572 }
5573 }
5574 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005575 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005576 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005577 }
5578 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005579 return filtered;
5580 } else {
5581 return unfiltered;
5582 }
5583 }
5584
Amith Yamasani27db4682013-03-30 17:07:47 -07005585 /*
5586 * packageName can be null. If not null, it should be used to filter out restricted accounts
5587 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005588 *
5589 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5590 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005591 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005592 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005593 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005594 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005595 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5596 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005597 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005598 Account[] accounts;
5599 synchronized (userAccounts.cacheLock) {
5600 accounts = userAccounts.accountCache.get(accountType);
5601 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005602 if (accounts == null) {
5603 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005604 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005605 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5606 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005607 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005608 } else {
5609 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005610 Account[] accountsArray;
5611 synchronized (userAccounts.cacheLock) {
5612 for (Account[] accounts : userAccounts.accountCache.values()) {
5613 totalLength += accounts.length;
5614 }
5615 if (totalLength == 0) {
5616 return EMPTY_ACCOUNT_ARRAY;
5617 }
5618 accountsArray = new Account[totalLength];
5619 totalLength = 0;
5620 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5621 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5622 accountsOfType.length);
5623 totalLength += accountsOfType.length;
5624 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005625 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005626 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005627 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005628 }
5629 }
5630
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005631 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005632 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005633 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005634 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005635 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005636 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005637 }
5638 if (value == null) {
5639 userDataForAccount.remove(key);
5640 } else {
5641 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005642 }
5643 }
5644
Carlos Valdivia91979be2015-05-22 14:11:35 -07005645 protected String readCachedTokenInternal(
5646 UserAccounts accounts,
5647 Account account,
5648 String tokenType,
5649 String callingPackage,
5650 byte[] pkgSigDigest) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005651 synchronized (accounts.dbLock) {
5652 synchronized (accounts.cacheLock) {
5653 return accounts.accountTokenCaches.get(
5654 account, tokenType, callingPackage, pkgSigDigest);
5655 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07005656 }
5657 }
5658
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005659 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005660 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005661 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005662 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005663 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005664 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005665 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005666 }
5667 if (value == null) {
5668 authTokensForAccount.remove(key);
5669 } else {
5670 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005671 }
5672 }
5673
Amith Yamasani04e0d262012-02-14 11:50:53 -08005674 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5675 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005676 // Fast path - check if account is already cached
5677 synchronized (accounts.cacheLock) {
5678 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5679 if (authTokensForAccount != null) {
5680 return authTokensForAccount.get(authTokenType);
5681 }
5682 }
5683 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005684 synchronized (accounts.dbLock) {
5685 synchronized (accounts.cacheLock) {
5686 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5687 if (authTokensForAccount == null) {
5688 // need to populate the cache for this account
5689 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
5690 accounts.authTokenCache.put(account, authTokensForAccount);
5691 }
5692 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08005693 }
Fred Quintana56285a62010-12-02 14:20:51 -08005694 }
5695 }
5696
Simranjit Kohli858511c2016-03-10 18:36:11 +00005697 protected String readUserDataInternalLocked(
5698 UserAccounts accounts, Account account, String key) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005699 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005700 if (userDataForAccount == null) {
5701 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005702 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005703 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005704 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005705 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005706 }
5707
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005708 private Context getContextForUser(UserHandle user) {
5709 try {
5710 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5711 } catch (NameNotFoundException e) {
5712 // Default to mContext, not finding the package system is running as is unlikely.
5713 return mContext;
5714 }
5715 }
Sandra Kwan78812282015-11-04 11:19:47 -08005716
5717 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5718 try {
5719 response.onResult(result);
5720 } catch (RemoteException e) {
5721 // if the caller is dead then there is no one to care about remote
5722 // exceptions
5723 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5724 Log.v(TAG, "failure while notifying response", e);
5725 }
5726 }
5727 }
5728
5729 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5730 String errorMessage) {
5731 try {
5732 response.onError(errorCode, errorMessage);
5733 } catch (RemoteException e) {
5734 // if the caller is dead then there is no one to care about remote
5735 // exceptions
5736 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5737 Log.v(TAG, "failure while notifying response", e);
5738 }
5739 }
5740 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005741
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005742 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005743 private final Object mLock = new Object();
5744
5745 @GuardedBy("mLock")
5746 private AccountManagerBackupHelper mBackupHelper;
5747
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005748 @Override
5749 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5750 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5751 if (account == null) {
5752 Slog.w(TAG, "account cannot be null");
5753 return;
5754 }
5755 if (packageName == null) {
5756 Slog.w(TAG, "packageName cannot be null");
5757 return;
5758 }
5759 if (userId < UserHandle.USER_SYSTEM) {
5760 Slog.w(TAG, "user id must be concrete");
5761 return;
5762 }
5763 if (callback == null) {
5764 Slog.w(TAG, "callback cannot be null");
5765 return;
5766 }
5767
Svet Ganovf6d424f12016-09-20 20:18:53 -07005768 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5769 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005770 Bundle result = new Bundle();
5771 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5772 callback.sendResult(result);
5773 return;
5774 }
5775
5776 final int uid;
5777 try {
5778 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5779 } catch (NameNotFoundException e) {
5780 Slog.e(TAG, "Unknown package " + packageName);
5781 return;
5782 }
5783
5784 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005785 final UserAccounts userAccounts;
5786 synchronized (mUsers) {
5787 userAccounts = mUsers.get(userId);
5788 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04005789 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005790 doNotification(userAccounts, account, null, intent, packageName, userId);
5791 }
5792
5793 @Override
5794 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5795 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5796 mAppPermissionChangeListeners.add(listener);
5797 }
5798
5799 @Override
5800 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5801 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005802 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005803
5804 @Override
5805 public byte[] backupAccountAccessPermissions(int userId) {
5806 synchronized (mLock) {
5807 if (mBackupHelper == null) {
5808 mBackupHelper = new AccountManagerBackupHelper(
5809 AccountManagerService.this, this);
5810 }
5811 return mBackupHelper.backupAccountAccessPermissions(userId);
5812 }
5813 }
5814
5815 @Override
5816 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5817 synchronized (mLock) {
5818 if (mBackupHelper == null) {
5819 mBackupHelper = new AccountManagerBackupHelper(
5820 AccountManagerService.this, this);
5821 }
5822 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5823 }
5824 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005825 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005826
5827 @VisibleForTesting
5828 static class Injector {
5829 private final Context mContext;
5830
5831 public Injector(Context context) {
5832 mContext = context;
5833 }
5834
5835 Looper getMessageHandlerLooper() {
5836 ServiceThread serviceThread = new ServiceThread(TAG,
5837 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5838 serviceThread.start();
5839 return serviceThread.getLooper();
5840 }
5841
5842 Context getContext() {
5843 return mContext;
5844 }
5845
5846 void addLocalService(AccountManagerInternal service) {
5847 LocalServices.addService(AccountManagerInternal.class, service);
5848 }
5849
5850 String getDeDatabaseName(int userId) {
5851 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5852 AccountsDb.DE_DATABASE_NAME);
5853 return databaseFile.getPath();
5854 }
5855
5856 String getCeDatabaseName(int userId) {
5857 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5858 AccountsDb.CE_DATABASE_NAME);
5859 return databaseFile.getPath();
5860 }
5861
5862 String getPreNDatabaseName(int userId) {
5863 File systemDir = Environment.getDataSystemDirectory();
5864 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5865 PRE_N_DATABASE_NAME);
5866 if (userId == 0) {
5867 // Migrate old file, if it exists, to the new location.
5868 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005869 // accidentally created in the old location,
5870 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005871 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5872 if (oldFile.exists() && !databaseFile.exists()) {
5873 // Check for use directory; create if it doesn't exist, else renameTo will fail
5874 File userDir = Environment.getUserSystemDirectory(userId);
5875 if (!userDir.exists()) {
5876 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005877 throw new IllegalStateException(
5878 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005879 }
5880 }
5881 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005882 throw new IllegalStateException(
5883 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005884 }
5885 }
5886 }
5887 return databaseFile.getPath();
5888 }
5889
5890 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5891 return new AccountAuthenticatorCache(mContext);
5892 }
5893
5894 INotificationManager getNotificationManager() {
5895 return NotificationManager.getService();
5896 }
5897 }
Fred Quintana60307342009-03-24 22:48:12 -07005898}