blob: d996ee282ef9ae1e34d7e225be97cd3b9df27817 [file] [log] [blame]
Fred Quintana60307342009-03-24 22:48:12 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.accounts;
Fred Quintana60307342009-03-24 22:48:12 -070018
Doug Zongker885cfc232009-10-21 16:52:44 -070019import android.Manifest;
Carlos Valdivia91979be2015-05-22 14:11:35 -070020import android.accounts.AbstractAccountAuthenticator;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080021import android.accounts.Account;
22import android.accounts.AccountAndUser;
23import android.accounts.AccountAuthenticatorResponse;
24import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070025import android.accounts.AccountManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080026import android.accounts.AuthenticatorDescription;
Amith Yamasani23c8b962013-04-10 13:37:18 -070027import android.accounts.CantAddAccountActivity;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080028import android.accounts.GrantCredentialsPermissionActivity;
29import android.accounts.IAccountAuthenticator;
30import android.accounts.IAccountAuthenticatorResponse;
31import android.accounts.IAccountManager;
32import android.accounts.IAccountManagerResponse;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070033import android.annotation.IntRange;
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070034import android.annotation.NonNull;
Svet Ganovf6d424f12016-09-20 20:18:53 -070035import android.annotation.Nullable;
Brett Chabot3b4fcbc2011-01-09 13:41:02 -080036import android.app.ActivityManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070037import android.app.ActivityThread;
Svetoslavf3f02ac2015-09-08 14:36:35 -070038import android.app.AppOpsManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070039import android.app.INotificationManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070040import android.app.Notification;
41import android.app.NotificationManager;
42import android.app.PendingIntent;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000043import android.app.admin.DeviceAdminInfo;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010044import android.app.admin.DevicePolicyManager;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000045import android.app.admin.DevicePolicyManagerInternal;
Fred Quintanaa698f422009-04-08 19:14:54 -070046import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070047import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070048import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070051import android.content.IntentSender;
Fred Quintanab839afc2009-10-14 15:57:28 -070052import android.content.ServiceConnection;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -080053import android.content.pm.ActivityInfo;
Doug Zongker885cfc232009-10-21 16:52:44 -070054import android.content.pm.ApplicationInfo;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070055import android.content.pm.IPackageManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070056import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070057import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070058import android.content.pm.PackageManager.NameNotFoundException;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070059import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070060import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070061import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070062import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070063import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070064import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070065import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070066import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070067import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080068import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070069import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070070import android.os.IBinder;
71import android.os.Looper;
72import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070073import android.os.Parcel;
Amith Yamasani27db4682013-03-30 17:07:47 -070074import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070075import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070076import android.os.RemoteException;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080077import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070078import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070079import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070080import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070081import android.text.TextUtils;
82import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070083import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070084import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080085import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070086import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070087
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070088import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070089import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070090import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070091import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040092import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050093import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080094import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060095import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080096import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -070097import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000098import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -070099import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600100import com.android.server.SystemService;
101
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700102import com.google.android.collect.Lists;
103import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700104
Oscar Montemayora8529f62009-11-18 10:14:20 -0800105import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700106import java.io.FileDescriptor;
107import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800108import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700109import java.security.MessageDigest;
110import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700111import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700112import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800113import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700114import java.util.Collection;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700115import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700116import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700117import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800118import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700119import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800120import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800121import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700122import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700123import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700124import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700125import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700126import java.util.concurrent.atomic.AtomicInteger;
127import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700128
Fred Quintana60307342009-03-24 22:48:12 -0700129/**
130 * A system service that provides account, password, and authtoken management for all
131 * accounts on the device. Some of these calls are implemented with the help of the corresponding
132 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
133 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700134 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700135 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700136 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700137public class AccountManagerService
138 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800139 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700140 private static final String TAG = "AccountManagerService";
141
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600142 public static class Lifecycle extends SystemService {
143 private AccountManagerService mService;
144
145 public Lifecycle(Context context) {
146 super(context);
147 }
148
149 @Override
150 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700151 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600152 publishBinderService(Context.ACCOUNT_SERVICE, mService);
153 }
154
155 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600156 public void onUnlockUser(int userHandle) {
157 mService.onUnlockUser(userHandle);
158 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700159
160 @Override
161 public void onCleanupUser(int userHandle) {
162 mService.onCleanupUser(userHandle);
163 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600164 }
165
Svet Ganov5d09c992016-09-07 09:57:41 -0700166 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700167
Fred Quintana56285a62010-12-02 14:20:51 -0800168 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700169 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700170 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700171 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800172
Svet Ganov5d09c992016-09-07 09:57:41 -0700173 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700174
Fred Quintana60307342009-03-24 22:48:12 -0700175 // Messages that can be sent on mHandler
176 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700177 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700178
Fred Quintana56285a62010-12-02 14:20:51 -0800179 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700180 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700181 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800182
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800183 private static final int SIGNATURE_CHECK_MISMATCH = 0;
184 private static final int SIGNATURE_CHECK_MATCH = 1;
185 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
186
Carlos Valdivia91979be2015-05-22 14:11:35 -0700187 static {
188 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800189 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
190 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700191 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700192
193 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Chris Wren282cfef2017-03-27 15:01:44 -0400194 private final AtomicInteger mNotificationIds =
195 new AtomicInteger(SystemMessage.ACCOUNT_MANAGER_BASE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700196
Amith Yamasani04e0d262012-02-14 11:50:53 -0800197 static class UserAccounts {
198 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700199 final AccountsDb accountsDb;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800200 private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
201 credentialsPermissionNotificationIds =
202 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
203 private final HashMap<Account, Integer> signinRequiredNotificationIds =
204 new HashMap<Account, Integer>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700205 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700206 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800207 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700208 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800209 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700210 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800211 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700212 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700213 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700214 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700215 /** protected by the {@link #cacheLock} */
216 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700217
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700218 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700219 * type -> (packageName -> number of active receivers)
220 * type == null is used to get notifications about all account types
221 */
222 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800223
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700224 /**
225 * protected by the {@link #cacheLock}
226 *
227 * Caches the previous names associated with an account. Previous names
228 * should be cached because we expect that when an Account is renamed,
229 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
230 * want to know if the accounts they care about have been renamed.
231 *
232 * The previous names are wrapped in an {@link AtomicReference} so that
233 * we can distinguish between those accounts with no previous names and
234 * those whose previous names haven't been cached (yet).
235 */
236 private final HashMap<Account, AtomicReference<String>> previousNameCache =
237 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800238
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700239 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700240 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700241
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700242 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800243 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700244 synchronized (dbLock) {
245 synchronized (cacheLock) {
246 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
247 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800248 }
249 }
250 }
251
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700252 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600253 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700254 // Not thread-safe. Only use in synchronized context
255 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700256 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
257 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800258
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700259 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700260 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700261
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700262 /**
263 * This should only be called by system code. One should only call this after the service
264 * has started.
265 * @return a reference to the AccountManagerService instance
266 * @hide
267 */
268 public static AccountManagerService getSingleton() {
269 return sThis.get();
270 }
Fred Quintana60307342009-03-24 22:48:12 -0700271
Fyodor Kupolovda993802016-09-21 14:47:10 -0700272 public AccountManagerService(Injector injector) {
273 mInjector = injector;
274 mContext = injector.getContext();
275 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700276 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700277 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
278 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800279 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700280
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700281 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800282
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800283 IntentFilter intentFilter = new IntentFilter();
284 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
285 intentFilter.addDataScheme("package");
286 mContext.registerReceiver(new BroadcastReceiver() {
287 @Override
288 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700289 // Don't delete accounts when updating a authenticator's
290 // package.
291 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700292 /* Purging data requires file io, don't block the main thread. This is probably
293 * less than ideal because we are introducing a race condition where old grants
294 * could be exercised until they are purged. But that race condition existed
295 * anyway with the broadcast receiver.
296 *
297 * Ideally, we would completely clear the cache, purge data from the database,
298 * and then rebuild the cache. All under the cache lock. But that change is too
299 * large at this point.
300 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800301 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700302 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700303 @Override
304 public void run() {
305 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800306 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800307 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700308 }
309 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700310 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700311 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800312 }
313 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800314
Fyodor Kupolovda993802016-09-21 14:47:10 -0700315 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700316
317 // Need to cancel account request notifications if the update/install can access the account
318 new PackageMonitor() {
319 @Override
320 public void onPackageAdded(String packageName, int uid) {
321 // Called on a handler, and running as the system
322 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
323 }
324
325 @Override
326 public void onPackageUpdateFinished(String packageName, int uid) {
327 // Called on a handler, and running as the system
328 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
329 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700330 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700331
332 // Cancel account request notification if an app op was preventing the account access
333 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
334 new AppOpsManager.OnOpChangedInternalListener() {
335 @Override
336 public void onOpChanged(int op, String packageName) {
337 try {
338 final int userId = ActivityManager.getCurrentUser();
339 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
340 final int mode = mAppOpsManager.checkOpNoThrow(
341 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
342 if (mode == AppOpsManager.MODE_ALLOWED) {
343 final long identity = Binder.clearCallingIdentity();
344 try {
345 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
346 } finally {
347 Binder.restoreCallingIdentity(identity);
348 }
349 }
350 } catch (NameNotFoundException e) {
351 /* ignore */
352 }
353 }
354 });
355
356 // Cancel account request notification if a permission was preventing the account access
357 mPackageManager.addOnPermissionsChangeListener(
358 (int uid) -> {
359 Account[] accounts = null;
360 String[] packageNames = mPackageManager.getPackagesForUid(uid);
361 if (packageNames != null) {
362 final int userId = UserHandle.getUserId(uid);
363 final long identity = Binder.clearCallingIdentity();
364 try {
365 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800366 // if app asked for permission we need to cancel notification even
367 // for O+ applications.
368 if (mPackageManager.checkPermission(
369 Manifest.permission.GET_ACCOUNTS,
370 packageName) != PackageManager.PERMISSION_GRANTED) {
371 continue;
372 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700373
374 if (accounts == null) {
375 accounts = getAccountsAsUser(null, userId, "android");
376 if (ArrayUtils.isEmpty(accounts)) {
377 return;
378 }
379 }
380
381 for (Account account : accounts) {
382 cancelAccountAccessRequestNotificationIfNeeded(
383 account, uid, packageName, true);
384 }
385 }
386 } finally {
387 Binder.restoreCallingIdentity(identity);
388 }
389 }
390 });
391 }
392
393 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
394 boolean checkAccess) {
395 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
396 for (Account account : accounts) {
397 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
398 }
399 }
400
401 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
402 boolean checkAccess) {
403 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
404 for (Account account : accounts) {
405 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
406 }
407 }
408
409 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
410 boolean checkAccess) {
411 String[] packageNames = mPackageManager.getPackagesForUid(uid);
412 if (packageNames != null) {
413 for (String packageName : packageNames) {
414 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
415 packageName, checkAccess);
416 }
417 }
418 }
419
420 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
421 int uid, String packageName, boolean checkAccess) {
422 if (!checkAccess || hasAccountAccess(account, packageName,
423 UserHandle.getUserHandleForUid(uid))) {
424 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700425 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700426 UserHandle.getUserHandleForUid(uid));
427 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800428 }
429
Dianne Hackborn164371f2013-10-01 19:10:13 -0700430 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800431 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800432 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800433 Bundle.setDefusable(extras, true);
434
435 final int callingUid = Binder.getCallingUid();
436 if (Log.isLoggable(TAG, Log.VERBOSE)) {
437 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
438 + ", pid " + Binder.getCallingPid());
439 }
440 Preconditions.checkNotNull(account, "account cannot be null");
441 int userId = UserHandle.getCallingUserId();
442 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
443 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
444 callingUid, account.type);
445 throw new SecurityException(msg);
446 }
447 /*
448 * Child users are not allowed to add accounts. Only the accounts that are shared by the
449 * parent profile can be added to child profile.
450 *
451 * TODO: Only allow accounts that were shared to be added by a limited user.
452 */
453 // fails if the account already exists
454 long identityToken = clearCallingIdentity();
455 try {
456 UserAccounts accounts = getUserAccounts(userId);
457 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800458 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800459 } finally {
460 restoreCallingIdentity(identityToken);
461 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700462 }
463
464 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800465 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
466 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800467 int callingUid = Binder.getCallingUid();
468 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
469 List<String> managedTypes =
470 getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
471
472 if ((accountType != null && !managedTypes.contains(accountType))
473 || (accountType == null && !isSystemUid)) {
474 throw new SecurityException(
475 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
476 + callingUid + " with packageName=" + packageName);
477 }
478 if (accountType != null) {
479 managedTypes = new ArrayList<String>();
480 managedTypes.add(accountType);
481 }
482
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800483 long identityToken = clearCallingIdentity();
484 try {
485 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
486 getUserAccounts(UserHandle.getUserId(callingUid)));
487 } finally {
488 restoreCallingIdentity(identityToken);
489 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800490 }
491
492 /*
493 * accountTypes may not be null
494 */
495 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
496 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
497 int uid = 0;
498 try {
499 uid = mPackageManager.getPackageUidAsUser(packageName,
500 UserHandle.getUserId(callingUid));
501 } catch (NameNotFoundException e) {
502 Log.d(TAG, "Package not found " + e.getMessage());
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800503 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800504 }
505
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800506 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800507 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700508 synchronized (accounts.dbLock) {
509 synchronized (accounts.cacheLock) {
510 final Account[] accountsOfType = accounts.accountCache.get(accountType);
511 if (accountsOfType != null) {
512 for (Account account : accountsOfType) {
513 result.put(account,
514 resolveAccountVisibility(account, packageName, accounts));
515 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800516 }
517 }
518 }
519 }
520 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800521 }
522
523 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800524 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700525 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700526 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800527 int userId = UserHandle.getUserId(callingUid);
528 UserAccounts accounts = getUserAccounts(userId);
529 if (!isAccountManagedByCaller(account.type, callingUid, userId)
530 && !isSystemUid(callingUid)) {
531 String msg =
532 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700533 throw new SecurityException(msg);
534 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700535 synchronized (accounts.dbLock) {
536 synchronized (accounts.cacheLock) {
537 return getPackagesAndVisibilityForAccountLocked(account, accounts);
538 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700539 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800540 }
541
542 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700543 * Returns Map with all package names and visibility values for given account.
544 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800545 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800546 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800547 * @param accounts UserAccount that currently hosts the account and application
548 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700549 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800550 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700551 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800552 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700553 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
554 if (accountVisibility == null) {
555 Log.d(TAG, "Visibility was not initialized");
556 accountVisibility = new HashMap<>();
557 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800558 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700559 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700560 }
561
562 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700563 public int getAccountVisibility(Account account, String packageName) {
564 Preconditions.checkNotNull(account, "account cannot be null");
565 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800566 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700567 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
568 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800569 && !isSystemUid(callingUid)) {
570 String msg = String.format(
571 "uid %s cannot get secrets for accounts of type: %s",
572 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700573 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800574 throw new SecurityException(msg);
575 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700576 return resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800577 }
578
579 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800580 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800581 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800582 * @param account The account to check visibility.
583 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800584 * @param accounts UserAccount that currently hosts the account and application
585 *
586 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
587 *
588 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700589 private int getAccountVisibilityFromCache(Account account, String packageName,
590 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700591 synchronized (accounts.cacheLock) {
592 Map<String, Integer> accountVisibility =
593 getPackagesAndVisibilityForAccountLocked(account, accounts);
594 Integer visibility = accountVisibility.get(packageName);
595 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800596 }
597 }
598
599 /**
600 * Method which handles default values for Account visibility.
601 *
602 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800603 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800604 * @param accounts UserAccount that currently hosts the account and application
605 *
606 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
607 *
608 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800609 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800610 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800611 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800612 int uid = -1;
613 try {
614 long identityToken = clearCallingIdentity();
615 try {
616 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
617 } finally {
618 restoreCallingIdentity(identityToken);
619 }
620 } catch (NameNotFoundException e) {
621 Log.d(TAG, "Package not found " + e.getMessage());
622 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800623 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800624
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800625 // System visibility can not be restricted.
626 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
627 return AccountManager.VISIBILITY_VISIBLE;
628 }
629
630 int signatureCheckResult =
631 checkPackageSignature(account.type, uid, accounts.userId);
632
633 // Authenticator can not restrict visibility to itself.
634 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
635 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
636 }
637
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800638 if (isSpecialPackageKey(packageName)) {
639 Log.d(TAG, "Package name is forbidden: " + packageName);
640 return AccountManager.VISIBILITY_NOT_VISIBLE;
641 }
642
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800643 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700644 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800645
646 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
647 return visibility;
648 }
649
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800650 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
651 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
652
653 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800654 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800655 return AccountManager.VISIBILITY_VISIBLE;
656 }
657 // Apps with READ_CONTACTS permission get visibility by default even post O.
658 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
659
660 boolean preO = isPreOApplication(packageName);
661 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
662 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800663 || canReadContacts || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800664 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
665 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700666 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800667 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800668 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
669 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
670 }
671 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700672 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800673 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800674 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
675 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
676 }
677 }
678 return visibility;
679 }
680
681 /**
682 * Checks targetSdk for a package;
683 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800684 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800685 *
686 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
687 * undefined
688 */
689 private boolean isPreOApplication(String packageName) {
690 try {
691 long identityToken = clearCallingIdentity();
692 ApplicationInfo applicationInfo;
693 try {
694 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
695 } finally {
696 restoreCallingIdentity(identityToken);
697 }
698
699 if (applicationInfo != null) {
700 int version = applicationInfo.targetSdkVersion;
701 return version < android.os.Build.VERSION_CODES.O;
702 }
703 return true;
704 } catch (NameNotFoundException e) {
705 Log.d(TAG, "Package not found " + e.getMessage());
706 return true;
707 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800708 }
709
710 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700711 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
712 Preconditions.checkNotNull(account, "account cannot be null");
713 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800714 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700715 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
716 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800717 && !isSystemUid(callingUid)) {
718 String msg = String.format(
719 "uid %s cannot get secrets for accounts of type: %s",
720 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700721 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800722 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700723 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700724 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
725 accounts);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700726 }
727
728 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800729 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700730 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800731 * @param account Account to update visibility.
732 * @param packageName Package name for which visibility is updated.
733 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800734 * @param notify if the flag is set applications will get notification about visibility change
735 * @param accounts UserAccount that currently hosts the account and application
736 *
737 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700738 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800739 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800740 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700741 synchronized (accounts.dbLock) {
742 synchronized (accounts.cacheLock) {
743 Map<String, Integer> packagesToVisibility;
744 if (notify) {
745 if (isSpecialPackageKey(packageName)) {
746 packagesToVisibility =
747 getRequestingPackages(account, accounts);
748 } else {
749 if (!packageExistsForUser(packageName, accounts.userId)) {
750 return false; // package is not installed.
751 }
752 packagesToVisibility = new HashMap<>();
753 packagesToVisibility.put(packageName,
754 resolveAccountVisibility(account, packageName, accounts));
755 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800756 } else {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700757 // Notifications will not be send.
758 if (!isSpecialPackageKey(packageName) &&
759 !packageExistsForUser(packageName, accounts.userId)) {
760 // package is not installed and not meta value.
761 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100762 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700763 packagesToVisibility = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800764 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700765
766 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800767 return false;
768 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800769
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700770 if (notify) {
771 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
772 .entrySet()) {
773 if (packageToVisibility.getValue()
774 != AccountManager.VISIBILITY_NOT_VISIBLE) {
775 notifyPackage(packageToVisibility.getKey(), accounts);
776 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700777 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700778 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700779 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700780 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800781 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700782 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700783 }
784
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700785 // Update account visibility in cache and database.
786 private boolean updateAccountVisibilityLocked(Account account, String packageName,
787 int newVisibility, UserAccounts accounts) {
788 final long accountId = accounts.accountsDb.findDeAccountId(account);
789 if (accountId < 0) {
790 return false;
791 }
792
793 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
794 try {
795 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
796 newVisibility)) {
797 return false;
798 }
799 } finally {
800 StrictMode.setThreadPolicy(oldPolicy);
801 }
802 Map<String, Integer> accountVisibility =
803 getPackagesAndVisibilityForAccountLocked(account, accounts);
804 accountVisibility.put(packageName, newVisibility);
805 return true;
806 }
807
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700808 @Override
809 public void registerAccountListener(String[] accountTypes, String opPackageName) {
810 int callingUid = Binder.getCallingUid();
811 mAppOpsManager.checkPackage(callingUid, opPackageName);
812 registerAccountListener(accountTypes, opPackageName,
813 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800814 }
815
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700816 private void registerAccountListener(String[] accountTypes, String opPackageName,
817 UserAccounts accounts) {
818 synchronized (accounts.mReceiversForType) {
819 if (accountTypes == null) {
820 // null for any type
821 accountTypes = new String[] {null};
822 }
823 for (String type : accountTypes) {
824 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
825 if (receivers == null) {
826 receivers = new HashMap<>();
827 accounts.mReceiversForType.put(type, receivers);
828 }
829 Integer cnt = receivers.get(opPackageName);
830 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800831 }
832 }
833 }
834
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700835 @Override
836 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
837 int callingUid = Binder.getCallingUid();
838 mAppOpsManager.checkPackage(callingUid, opPackageName);
839 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
840 synchronized (accounts.mReceiversForType) {
841 if (accountTypes == null) {
842 // null for any type
843 accountTypes = new String[] {null};
844 }
845 for (String type : accountTypes) {
846 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
847 if (receivers == null || receivers.get(opPackageName) == null) {
848 throw new IllegalArgumentException("attempt to unregister wrong receiver");
849 }
850 Integer cnt = receivers.get(opPackageName);
851 if (cnt == 1) {
852 receivers.remove(opPackageName);
853 } else {
854 receivers.put(opPackageName, cnt - 1);
855 }
856 }
857 }
858 }
859
860 // Send notification to all packages which can potentially see the account
861 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
862 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
863 // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
864 // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
865 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
866 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
867 notifyPackage(packageToVisibility.getKey(), accounts);
868 }
869 }
870 }
871
872 /**
873 * Sends a direct intent to a package, notifying it of account visibility change.
874 *
875 * @param packageName to send Account to
876 * @param accounts UserAccount that currently hosts the account
877 */
878 private void notifyPackage(String packageName, UserAccounts accounts) {
879 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
880 intent.setPackage(packageName);
881 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
882 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
883 }
884
885 // Returns a map from package name to visibility, for packages subscribed
886 // to notifications about any account type, or type of provided account
887 // account type or all types.
888 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
889 Set<String> packages = new HashSet<>();
890 synchronized (accounts.mReceiversForType) {
891 for (String type : new String[] {account.type, null}) {
892 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
893 if (receivers != null) {
894 packages.addAll(receivers.keySet());
895 }
896 }
897 }
898 Map<String, Integer> result = new HashMap<>();
899 for (String packageName : packages) {
900 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
901 }
902 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800903 }
904
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800905 private boolean packageExistsForUser(String packageName, int userId) {
906 try {
907 long identityToken = clearCallingIdentity();
908 try {
909 mPackageManager.getPackageUidAsUser(packageName, userId);
910 return true; // package exist
911 } finally {
912 restoreCallingIdentity(identityToken);
913 }
914 } catch (NameNotFoundException e) {
915 return false;
916 }
917 }
918
919 /**
920 * Returns true if packageName is one of special values.
921 */
922 private boolean isSpecialPackageKey(String packageName) {
923 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
924 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
925 }
926
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800927 private void sendAccountsChangedBroadcast(int userId) {
928 Log.i(TAG, "the accounts changed, sending broadcast of "
929 + ACCOUNTS_CHANGED_INTENT.getAction());
930 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700931 }
932
933 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700934 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
935 throws RemoteException {
936 try {
937 return super.onTransact(code, data, reply, flags);
938 } catch (RuntimeException e) {
939 // The account manager only throws security exceptions, so let's
940 // log all others.
941 if (!(e instanceof SecurityException)) {
942 Slog.wtf(TAG, "Account Manager Crash", e);
943 }
944 throw e;
945 }
946 }
947
Amith Yamasani258848d2012-08-10 17:06:33 -0700948 private UserManager getUserManager() {
949 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700950 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700951 }
952 return mUserManager;
953 }
954
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700955 /**
956 * Validate internal set of accounts against installed authenticators for
957 * given user. Clears cached authenticators before validating.
958 */
959 public void validateAccounts(int userId) {
960 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700961 // Invalidate user-specific cache to make sure we catch any
962 // removed authenticators.
963 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
964 }
965
966 /**
967 * Validate internal set of accounts against installed authenticators for
968 * given user. Clear cached authenticators before validating when requested.
969 */
970 private void validateAccountsInternal(
971 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700972 if (Log.isLoggable(TAG, Log.DEBUG)) {
973 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700974 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600975 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700976 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700977
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700978 if (invalidateAuthenticatorCache) {
979 mAuthenticatorCache.invalidateCache(accounts.userId);
980 }
981
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700982 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
983 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700984 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700985
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700986 synchronized (accounts.dbLock) {
987 synchronized (accounts.cacheLock) {
988 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800989
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700990 // Get a map of stored authenticator types to UID
991 final AccountsDb accountsDb = accounts.accountsDb;
992 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
993 // Create a list of authenticator type whose previous uid no longer exists
994 HashSet<String> obsoleteAuthType = Sets.newHashSet();
995 SparseBooleanArray knownUids = null;
996 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
997 String type = authToUidEntry.getKey();
998 int uid = authToUidEntry.getValue();
999 Integer knownUid = knownAuth.get(type);
1000 if (knownUid != null && uid == knownUid) {
1001 // Remove it from the knownAuth list if it's unchanged.
1002 knownAuth.remove(type);
1003 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001004 /*
1005 * The authenticator is presently not cached and should only be triggered
1006 * when we think an authenticator has been removed (or is being updated).
1007 * But we still want to check if any data with the associated uid is
1008 * around. This is an (imperfect) signal that the package may be updating.
1009 *
1010 * A side effect of this is that an authenticator sharing a uid with
1011 * multiple apps won't get its credentials wiped as long as some app with
1012 * that uid is still on the device. But I suspect that this is a rare case.
1013 * And it isn't clear to me how an attacker could really exploit that
1014 * feature.
1015 *
1016 * The upshot is that we don't have to worry about accounts getting
1017 * uninstalled while the authenticator's package is being updated.
1018 *
1019 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001020 if (knownUids == null) {
1021 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1022 }
1023 if (!knownUids.get(uid)) {
1024 // The authenticator is not presently available to the cache. And the
1025 // package no longer has a data directory (so we surmise it isn't
1026 // updating). So purge its data from the account databases.
1027 obsoleteAuthType.add(type);
1028 // And delete it from the TABLE_META
1029 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1030 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001031 }
1032 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001033
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001034 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1035 // been re-enabled (after being updated for example), then we just overwrite the old
1036 // values.
1037 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1038 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1039 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001040
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001041 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1042 try {
1043 accounts.accountCache.clear();
1044 final HashMap<String, ArrayList<String>> accountNamesByType
1045 = new LinkedHashMap<>();
1046 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1047 final long accountId = accountEntry.getKey();
1048 final Account account = accountEntry.getValue();
1049 if (obsoleteAuthType.contains(account.type)) {
1050 Slog.w(TAG, "deleting account " + account.name + " because type "
1051 + account.type
1052 + "'s registered authenticator no longer exist.");
1053 Map<String, Integer> packagesToVisibility =
1054 getRequestingPackages(account, accounts);
1055 accountsDb.beginTransaction();
1056 try {
1057 accountsDb.deleteDeAccount(accountId);
1058 // Also delete from CE table if user is unlocked; if user is
1059 // currently locked the account will be removed later by
1060 // syncDeCeAccountsLocked
1061 if (userUnlocked) {
1062 accountsDb.deleteCeAccount(accountId);
1063 }
1064 accountsDb.setTransactionSuccessful();
1065 } finally {
1066 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001067 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001068 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001069
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001070 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1071 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001072
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001073 accounts.userDataCache.remove(account);
1074 accounts.authTokenCache.remove(account);
1075 accounts.accountTokenCaches.remove(account);
1076 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001077
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001078 for (Entry<String, Integer> packageToVisibility :
1079 packagesToVisibility.entrySet()) {
1080 if (packageToVisibility.getValue()
1081 != AccountManager.VISIBILITY_NOT_VISIBLE) {
1082 notifyPackage(packageToVisibility.getKey(), accounts);
1083 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001084 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001085 } else {
1086 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1087 if (accountNames == null) {
1088 accountNames = new ArrayList<>();
1089 accountNamesByType.put(account.type, accountNames);
1090 }
1091 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001092 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001093 }
1094 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1095 final String accountType = cur.getKey();
1096 final ArrayList<String> accountNames = cur.getValue();
1097 final Account[] accountsForType = new Account[accountNames.size()];
1098 for (int i = 0; i < accountsForType.length; i++) {
1099 accountsForType[i] = new Account(accountNames.get(i), accountType,
1100 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001101 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001102 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001103 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001104 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1105 } finally {
1106 if (accountDeleted) {
1107 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001108 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001109 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001110 }
1111 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001112 }
1113
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001114 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1115 // Get the UIDs of all apps that might have data on the device. We want
1116 // to preserve user data if the app might otherwise be storing data.
1117 List<PackageInfo> pkgsWithData =
1118 mPackageManager.getInstalledPackagesAsUser(
1119 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1120 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1121 for (PackageInfo pkgInfo : pkgsWithData) {
1122 if (pkgInfo.applicationInfo != null
1123 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1124 knownUids.put(pkgInfo.applicationInfo.uid, true);
1125 }
1126 }
1127 return knownUids;
1128 }
1129
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001130 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001131 Context context,
1132 int userId) {
1133 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001134 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1135 }
1136
1137 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1138 IAccountAuthenticatorCache authCache,
1139 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001140 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001141 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1142 .getAllServices(userId)) {
1143 knownAuth.put(service.type.type, service.uid);
1144 }
1145 return knownAuth;
1146 }
1147
Amith Yamasani04e0d262012-02-14 11:50:53 -08001148 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001149 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001150 }
1151
1152 protected UserAccounts getUserAccounts(int userId) {
1153 synchronized (mUsers) {
1154 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001155 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001156 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001157 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1158 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001159 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001160 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001161 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001162 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001163 validateAccounts = true;
1164 }
1165 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001166 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001167 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001168 synchronized (accounts.dbLock) {
1169 synchronized (accounts.cacheLock) {
1170 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1171 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1172 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001173 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001174 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001175 }
1176 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001177 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001178 }
1179 return accounts;
1180 }
1181 }
1182
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001183 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1184 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001185 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001186 if (!accountsToRemove.isEmpty()) {
1187 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1188 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001189 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1190 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001191
1192 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001193 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001194 }
1195 }
1196 }
1197
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001198 private void purgeOldGrantsAll() {
1199 synchronized (mUsers) {
1200 for (int i = 0; i < mUsers.size(); i++) {
1201 purgeOldGrants(mUsers.valueAt(i));
1202 }
1203 }
1204 }
1205
1206 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001207 synchronized (accounts.dbLock) {
1208 synchronized (accounts.cacheLock) {
1209 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1210 for (int uid : uids) {
1211 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1212 if (packageExists) {
1213 continue;
1214 }
1215 Log.d(TAG, "deleting grants for UID " + uid
1216 + " because its package is no longer installed");
1217 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001218 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001219 }
1220 }
1221 }
1222
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001223 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001224 if (isSpecialPackageKey(packageName)) {
1225 return;
1226 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001227 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001228 int numberOfUsers = mUsers.size();
1229 for (int i = 0; i < numberOfUsers; i++) {
1230 UserAccounts accounts = mUsers.valueAt(i);
1231 try {
1232 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1233 } catch (NameNotFoundException e) {
1234 // package does not exist - remove visibility values
1235 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001236 synchronized (accounts.dbLock) {
1237 synchronized (accounts.cacheLock) {
1238 for (Account account : accounts.visibilityCache.keySet()) {
1239 Map<String, Integer> accountVisibility =
1240 getPackagesAndVisibilityForAccountLocked(account, accounts);
1241 accountVisibility.remove(packageName);
1242 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001243 }
1244 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001245 }
1246 }
1247 }
1248 }
1249
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001250
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -07001251 private void onCleanupUser(int userId) {
1252 Log.i(TAG, "onCleanupUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001253 UserAccounts accounts;
1254 synchronized (mUsers) {
1255 accounts = mUsers.get(userId);
1256 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001257 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001258 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001259 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001260 synchronized (accounts.dbLock) {
1261 synchronized (accounts.cacheLock) {
1262 accounts.accountsDb.close();
1263 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001264 }
Amith Yamasani13593602012-03-22 16:16:17 -07001265 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001266 }
1267
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001268 @VisibleForTesting
1269 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001270 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1271 }
1272
1273 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001274 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1275 Log.v(TAG, "onUserUnlocked " + userId);
1276 }
1277 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001278 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001279 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001280 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001281 syncSharedAccounts(userId);
1282 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001283
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001284 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001285 // Check if there's a shared account that needs to be created as an account
1286 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1287 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001288 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001289 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001290 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001291 : UserHandle.USER_SYSTEM;
1292 if (parentUserId < 0) {
1293 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1294 return;
1295 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001296 for (Account sa : sharedAccounts) {
1297 if (ArrayUtils.contains(accounts, sa)) continue;
1298 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001299 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001300 }
1301 }
1302
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001303 @Override
1304 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001305 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001306 }
1307
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001308 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001309 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001310 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001311 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1312 Log.v(TAG, "getPassword: " + account
1313 + ", caller's uid " + Binder.getCallingUid()
1314 + ", pid " + Binder.getCallingPid());
1315 }
Fred Quintana382601f2010-03-25 12:25:10 -07001316 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001317 int userId = UserHandle.getCallingUserId();
1318 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001319 String msg = String.format(
1320 "uid %s cannot get secrets for accounts of type: %s",
1321 callingUid,
1322 account.type);
1323 throw new SecurityException(msg);
1324 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001325 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001326 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001327 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001328 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001329 } finally {
1330 restoreCallingIdentity(identityToken);
1331 }
1332 }
1333
Amith Yamasani04e0d262012-02-14 11:50:53 -08001334 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001335 if (account == null) {
1336 return null;
1337 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001338 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001339 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1340 return null;
1341 }
Fred Quintana31957f12009-10-21 13:43:10 -07001342
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001343 synchronized (accounts.dbLock) {
1344 synchronized (accounts.cacheLock) {
1345 return accounts.accountsDb
1346 .findAccountPasswordByNameAndType(account.name, account.type);
1347 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001348 }
1349 }
1350
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001351 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001352 public String getPreviousName(Account account) {
1353 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1354 Log.v(TAG, "getPreviousName: " + account
1355 + ", caller's uid " + Binder.getCallingUid()
1356 + ", pid " + Binder.getCallingPid());
1357 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001358 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001359 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001360 long identityToken = clearCallingIdentity();
1361 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001362 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001363 return readPreviousNameInternal(accounts, account);
1364 } finally {
1365 restoreCallingIdentity(identityToken);
1366 }
1367 }
1368
1369 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1370 if (account == null) {
1371 return null;
1372 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001373 synchronized (accounts.dbLock) {
1374 synchronized (accounts.cacheLock) {
1375 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1376 if (previousNameRef == null) {
1377 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1378 previousNameRef = new AtomicReference<>(previousName);
1379 accounts.previousNameCache.put(account, previousNameRef);
1380 return previousName;
1381 } else {
1382 return previousNameRef.get();
1383 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001384 }
1385 }
1386 }
1387
1388 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001389 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001390 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001391 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001392 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1393 account, key, callingUid, Binder.getCallingPid());
1394 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001395 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001396 Preconditions.checkNotNull(account, "account cannot be null");
1397 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001398 int userId = UserHandle.getCallingUserId();
1399 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001400 String msg = String.format(
1401 "uid %s cannot get user data for accounts of type: %s",
1402 callingUid,
1403 account.type);
1404 throw new SecurityException(msg);
1405 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001406 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001407 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1408 return null;
1409 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001410 long identityToken = clearCallingIdentity();
1411 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001412 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001413 if (!accountExistsCache(accounts, account)) {
1414 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001415 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001416 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001417 } finally {
1418 restoreCallingIdentity(identityToken);
1419 }
1420 }
1421
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001422 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001423 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001424 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001425 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1426 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001427 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001428 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001429 + ", pid " + Binder.getCallingPid());
1430 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001431 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001432 if (isCrossUser(callingUid, userId)) {
1433 throw new SecurityException(
1434 String.format(
1435 "User %s tying to get authenticator types for %s" ,
1436 UserHandle.getCallingUserId(),
1437 userId));
1438 }
1439
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001440 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001441 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001442 return getAuthenticatorTypesInternal(userId);
1443
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001444 } finally {
1445 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001446 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001447 }
1448
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001449 /**
1450 * Should only be called inside of a clearCallingIdentity block.
1451 */
1452 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001453 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001454 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1455 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1456 AuthenticatorDescription[] types =
1457 new AuthenticatorDescription[authenticatorCollection.size()];
1458 int i = 0;
1459 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1460 : authenticatorCollection) {
1461 types[i] = authenticator.type;
1462 i++;
1463 }
1464 return types;
1465 }
1466
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001467 private boolean isCrossUser(int callingUid, int userId) {
1468 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001469 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001470 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001471 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1472 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001473 }
1474
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001475 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001476 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001477 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001478 }
1479
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001480 @Override
1481 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001482 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001483 int callingUid = Binder.getCallingUid();
1484 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1485 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001486 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001487 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001488 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1489 final UserAccounts toAccounts = getUserAccounts(userTo);
1490 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001491 if (response != null) {
1492 Bundle result = new Bundle();
1493 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1494 try {
1495 response.onResult(result);
1496 } catch (RemoteException e) {
1497 Slog.w(TAG, "Failed to report error back to the client." + e);
1498 }
1499 }
1500 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001501 }
1502
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001503 Slog.d(TAG, "Copying account " + account.name
1504 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001505 long identityToken = clearCallingIdentity();
1506 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001507 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001508 false /* stripAuthTokenFromResult */, account.name,
1509 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001510 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001511 protected String toDebugString(long now) {
1512 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1513 + ", " + account.type;
1514 }
1515
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001516 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001517 public void run() throws RemoteException {
1518 mAuthenticator.getAccountCredentialsForCloning(this, account);
1519 }
1520
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001521 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001522 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001523 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001524 if (result != null
1525 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1526 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001527 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001528 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001529 super.onResult(result);
1530 }
1531 }
1532 }.bind();
1533 } finally {
1534 restoreCallingIdentity(identityToken);
1535 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001536 }
1537
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001538 @Override
1539 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001540 final int callingUid = Binder.getCallingUid();
1541 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1542 String msg = String.format(
1543 "accountAuthenticated( account: %s, callerUid: %s)",
1544 account,
1545 callingUid);
1546 Log.v(TAG, msg);
1547 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001548 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001549 int userId = UserHandle.getCallingUserId();
1550 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001551 String msg = String.format(
1552 "uid %s cannot notify authentication for accounts of type: %s",
1553 callingUid,
1554 account.type);
1555 throw new SecurityException(msg);
1556 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001557
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001558 if (!canUserModifyAccounts(userId, callingUid) ||
1559 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001560 return false;
1561 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001562
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001563 long identityToken = clearCallingIdentity();
1564 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001565 UserAccounts accounts = getUserAccounts(userId);
1566 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001567 } finally {
1568 restoreCallingIdentity(identityToken);
1569 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001570 }
1571
1572 private boolean updateLastAuthenticatedTime(Account account) {
1573 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001574 synchronized (accounts.dbLock) {
1575 synchronized (accounts.cacheLock) {
1576 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1577 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001578 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001579 }
1580
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001581 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001582 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1583 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001584 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001585 long id = clearCallingIdentity();
1586 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001587 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001588 false /* stripAuthTokenFromResult */, account.name,
1589 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001590 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001591 protected String toDebugString(long now) {
1592 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1593 + ", " + account.type;
1594 }
1595
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001596 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001597 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001598 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001599 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1600 if (acc.equals(account)) {
1601 mAuthenticator.addAccountFromCredentials(
1602 this, account, accountCredentials);
1603 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001604 }
1605 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001606 }
1607
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001608 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001609 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001610 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001611 // TODO: Anything to do if if succedded?
1612 // TODO: If it failed: Show error notification? Should we remove the shadow
1613 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001614 // TODO: what we do with the visibility?
1615
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001616 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001617 }
1618
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001619 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001620 public void onError(int errorCode, String errorMessage) {
1621 super.onError(errorCode, errorMessage);
1622 // TODO: Show error notification to user
1623 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1624 }
1625
1626 }.bind();
1627 } finally {
1628 restoreCallingIdentity(id);
1629 }
1630 }
1631
Amith Yamasani04e0d262012-02-14 11:50:53 -08001632 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001633 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001634 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001635 if (account == null) {
1636 return false;
1637 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001638 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001639 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1640 + " is locked. callingUid=" + callingUid);
1641 return false;
1642 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001643 synchronized (accounts.dbLock) {
1644 synchronized (accounts.cacheLock) {
1645 accounts.accountsDb.beginTransaction();
1646 try {
1647 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1648 Log.w(TAG, "insertAccountIntoDatabase: " + account
1649 + ", skipping since the account already exists");
1650 return false;
1651 }
1652 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1653 if (accountId < 0) {
1654 Log.w(TAG, "insertAccountIntoDatabase: " + account
1655 + ", skipping the DB insert failed");
1656 return false;
1657 }
1658 // Insert into DE table
1659 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1660 Log.w(TAG, "insertAccountIntoDatabase: " + account
1661 + ", skipping the DB insert failed");
1662 return false;
1663 }
1664 if (extras != null) {
1665 for (String key : extras.keySet()) {
1666 final String value = extras.getString(key);
1667 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1668 Log.w(TAG, "insertAccountIntoDatabase: " + account
1669 + ", skipping since insertExtra failed for key " + key);
1670 return false;
1671 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001672 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001673 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001674
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001675 if (packageToVisibility != null) {
1676 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1677 setAccountVisibility(account, entry.getKey() /* package */,
1678 entry.getValue() /* visibility */, false /* notify */,
1679 accounts);
1680 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001681 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001682 accounts.accountsDb.setTransactionSuccessful();
1683
1684 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1685 accountId,
1686 accounts, callingUid);
1687
1688 insertAccountIntoCacheLocked(accounts, account);
1689 } finally {
1690 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001691 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001692 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001693 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001694 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1695 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001696 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001697
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001698 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001699 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1700 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001701
Amith Yamasani5be347b2013-03-31 17:44:31 -07001702 return true;
1703 }
1704
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001705 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001706 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001707 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001708 }
1709 }
1710
Amith Yamasani5be347b2013-03-31 17:44:31 -07001711 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001712 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001713 * running, then clone the account too.
1714 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001715 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001716 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001717 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001718 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001719 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001720 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001721 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001722 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001723 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001724 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001725 }
1726 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001727 }
1728 }
1729
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001730 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001731 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001732 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001733 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001734 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001735 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1736 Log.v(TAG, "hasFeatures: " + account
1737 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001738 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001739 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001740 + ", pid " + Binder.getCallingPid());
1741 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001742 Preconditions.checkArgument(account != null, "account cannot be null");
1743 Preconditions.checkArgument(response != null, "response cannot be null");
1744 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001745 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001746 checkReadAccountsPermitted(callingUid, account.type, userId,
1747 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001748
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001749 long identityToken = clearCallingIdentity();
1750 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001751 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001752 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001753 } finally {
1754 restoreCallingIdentity(identityToken);
1755 }
1756 }
1757
1758 private class TestFeaturesSession extends Session {
1759 private final String[] mFeatures;
1760 private final Account mAccount;
1761
Amith Yamasani04e0d262012-02-14 11:50:53 -08001762 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001763 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001764 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001765 true /* stripAuthTokenFromResult */, account.name,
1766 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001767 mFeatures = features;
1768 mAccount = account;
1769 }
1770
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001771 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001772 public void run() throws RemoteException {
1773 try {
1774 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1775 } catch (RemoteException e) {
1776 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1777 }
1778 }
1779
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001780 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001781 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001782 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001783 IAccountManagerResponse response = getResponseAndClose();
1784 if (response != null) {
1785 try {
1786 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001787 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001788 return;
1789 }
Fred Quintana56285a62010-12-02 14:20:51 -08001790 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1791 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1792 + response);
1793 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001794 final Bundle newResult = new Bundle();
1795 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1796 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1797 response.onResult(newResult);
1798 } catch (RemoteException e) {
1799 // if the caller is dead then there is no one to care about remote exceptions
1800 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1801 Log.v(TAG, "failure while notifying response", e);
1802 }
1803 }
1804 }
1805 }
1806
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001807 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001808 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001809 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001810 + ", " + mAccount
1811 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1812 }
1813 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001814
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001815 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001816 public void renameAccount(
1817 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001818 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001819 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1820 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001821 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001822 + ", pid " + Binder.getCallingPid());
1823 }
1824 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001825 int userId = UserHandle.getCallingUserId();
1826 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001827 String msg = String.format(
1828 "uid %s cannot rename accounts of type: %s",
1829 callingUid,
1830 accountToRename.type);
1831 throw new SecurityException(msg);
1832 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001833 long identityToken = clearCallingIdentity();
1834 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001835 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001836 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001837 Bundle result = new Bundle();
1838 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1839 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001840 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1841 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001842 try {
1843 response.onResult(result);
1844 } catch (RemoteException e) {
1845 Log.w(TAG, e.getMessage());
1846 }
1847 } finally {
1848 restoreCallingIdentity(identityToken);
1849 }
1850 }
1851
1852 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001853 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001854 Account resultAccount = null;
1855 /*
1856 * Cancel existing notifications. Let authenticators
1857 * re-post notifications as required. But we don't know if
1858 * the authenticators have bound their notifications to
1859 * now stale account name data.
1860 *
1861 * With a rename api, we might not need to do this anymore but it
1862 * shouldn't hurt.
1863 */
1864 cancelNotification(
1865 getSigninRequiredNotificationId(accounts, accountToRename),
1866 new UserHandle(accounts.userId));
1867 synchronized(accounts.credentialsPermissionNotificationIds) {
1868 for (Pair<Pair<Account, String>, Integer> pair:
1869 accounts.credentialsPermissionNotificationIds.keySet()) {
1870 if (accountToRename.equals(pair.first.first)) {
1871 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1872 cancelNotification(id, new UserHandle(accounts.userId));
1873 }
1874 }
1875 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001876 synchronized (accounts.dbLock) {
1877 synchronized (accounts.cacheLock) {
1878 accounts.accountsDb.beginTransaction();
1879 Account renamedAccount = new Account(newName, accountToRename.type);
1880 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1881 Log.e(TAG, "renameAccount failed - account with new name already exists");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001882 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001883 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001884 try {
1885 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
1886 if (accountId >= 0) {
1887 accounts.accountsDb.renameCeAccount(accountId, newName);
1888 if (accounts.accountsDb.renameDeAccount(
1889 accountId, newName, accountToRename.name)) {
1890 accounts.accountsDb.setTransactionSuccessful();
1891 } else {
1892 Log.e(TAG, "renameAccount failed");
1893 return null;
1894 }
1895 } else {
1896 Log.e(TAG, "renameAccount failed - old account does not exist");
1897 return null;
1898 }
1899 } finally {
1900 accounts.accountsDb.endTransaction();
1901 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001902 /*
1903 * Database transaction was successful. Clean up cached
1904 * data associated with the account in the user profile.
1905 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001906 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001907 /*
1908 * Extract the data and token caches before removing the
1909 * old account to preserve the user data associated with
1910 * the account.
1911 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001912 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1913 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
1914 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
1915 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001916 /*
1917 * Update the cached data associated with the renamed
1918 * account.
1919 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001920 accounts.userDataCache.put(renamedAccount, tmpData);
1921 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1922 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
1923 accounts.previousNameCache.put(
1924 renamedAccount,
1925 new AtomicReference<>(accountToRename.name));
1926 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001927
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001928 int parentUserId = accounts.userId;
1929 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001930 /*
1931 * Owner or system user account was renamed, rename the account for
1932 * those users with which the account was shared.
1933 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001934 List<UserInfo> users = getUserManager().getUsers(true);
1935 for (UserInfo user : users) {
1936 if (user.isRestricted()
1937 && (user.restrictedProfileParentId == parentUserId)) {
1938 renameSharedAccountAsUser(accountToRename, newName, user.id);
1939 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001940 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001941 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001942
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001943 sendNotificationAccountUpdated(resultAccount, accounts);
1944 sendAccountsChangedBroadcast(accounts.userId);
1945 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001946 }
1947 return resultAccount;
1948 }
1949
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001950 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001951 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001952 return userInfo != null && userInfo.canHaveProfile();
1953 }
1954
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001955 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001956 public void removeAccount(IAccountManagerResponse response, Account account,
1957 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001958 removeAccountAsUser(
1959 response,
1960 account,
1961 expectActivityLaunch,
1962 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001963 }
1964
1965 @Override
1966 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001967 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001968 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001969 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1970 Log.v(TAG, "removeAccount: " + account
1971 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001972 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001973 + ", pid " + Binder.getCallingPid()
1974 + ", for user id " + userId);
1975 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001976 Preconditions.checkArgument(account != null, "account cannot be null");
1977 Preconditions.checkArgument(response != null, "response cannot be null");
1978
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001979 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001980 if (isCrossUser(callingUid, userId)) {
1981 throw new SecurityException(
1982 String.format(
1983 "User %s tying remove account for %s" ,
1984 UserHandle.getCallingUserId(),
1985 userId));
1986 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001987 /*
1988 * Only the system or authenticator should be allowed to remove accounts for that
1989 * authenticator. This will let users remove accounts (via Settings in the system) but not
1990 * arbitrary applications (like competing authenticators).
1991 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001992 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00001993 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1994 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001995 String msg = String.format(
1996 "uid %s cannot remove accounts of type: %s",
1997 callingUid,
1998 account.type);
1999 throw new SecurityException(msg);
2000 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002001 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002002 try {
2003 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2004 "User cannot modify accounts");
2005 } catch (RemoteException re) {
2006 }
2007 return;
2008 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002009 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002010 try {
2011 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2012 "User cannot modify accounts of this type (policy).");
2013 } catch (RemoteException re) {
2014 }
2015 return;
2016 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002017 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002018 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002019 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002020 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002021 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002022 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002023 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002024 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002025 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002026 }
2027 }
2028 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002029 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002030 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002031 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2032 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002033 accountId,
2034 accounts,
2035 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002036 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002037 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2038 } finally {
2039 restoreCallingIdentity(identityToken);
2040 }
2041 }
2042
2043 @Override
2044 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002045 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002046 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2047 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002048 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002049 + ", pid " + Binder.getCallingPid());
2050 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002051 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002052 if (account == null) {
2053 /*
2054 * Null accounts should result in returning false, as per
2055 * AccountManage.addAccountExplicitly(...) java doc.
2056 */
2057 Log.e(TAG, "account is null");
2058 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002059 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002060 String msg = String.format(
2061 "uid %s cannot explicitly add accounts of type: %s",
2062 callingUid,
2063 account.type);
2064 throw new SecurityException(msg);
2065 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002066 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002067 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002068 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002069 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2070 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002071 accountId,
2072 accounts,
2073 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002074 long identityToken = clearCallingIdentity();
2075 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002076 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002077 } finally {
2078 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002079 }
Fred Quintana60307342009-03-24 22:48:12 -07002080 }
2081
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002082 private class RemoveAccountSession extends Session {
2083 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002084 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002085 Account account, boolean expectActivityLaunch) {
2086 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002087 true /* stripAuthTokenFromResult */, account.name,
2088 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002089 mAccount = account;
2090 }
2091
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002092 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002093 protected String toDebugString(long now) {
2094 return super.toDebugString(now) + ", removeAccount"
2095 + ", account " + mAccount;
2096 }
2097
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002098 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002099 public void run() throws RemoteException {
2100 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2101 }
2102
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002103 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002104 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002105 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002106 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2107 && !result.containsKey(AccountManager.KEY_INTENT)) {
2108 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002109 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002110 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002111 }
2112 IAccountManagerResponse response = getResponseAndClose();
2113 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002114 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2115 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2116 + response);
2117 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002118 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002119 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002120 try {
2121 response.onResult(result2);
2122 } catch (RemoteException e) {
2123 // ignore
2124 }
2125 }
2126 }
2127 super.onResult(result);
2128 }
2129 }
2130
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002131 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002132 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002133 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002134 }
2135
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002136 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002137 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002138 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002139 if (!userUnlocked) {
2140 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2141 + " is still locked. CE data will be removed later");
2142 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002143 synchronized (accounts.dbLock) {
2144 synchronized (accounts.cacheLock) {
2145 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2146 accounts);
2147 accounts.accountsDb.beginTransaction();
2148 // Set to a dummy value, this will only be used if the database
2149 // transaction succeeds.
2150 long accountId = -1;
2151 try {
2152 accountId = accounts.accountsDb.findDeAccountId(account);
2153 if (accountId >= 0) {
2154 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002155 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002156 // always delete from CE table if CE storage is available
2157 // DE account could be removed while CE was locked
2158 if (userUnlocked) {
2159 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2160 if (ceAccountId >= 0) {
2161 accounts.accountsDb.deleteCeAccount(ceAccountId);
2162 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002163 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002164 accounts.accountsDb.setTransactionSuccessful();
2165 } finally {
2166 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002167 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002168 if (isChanged) {
2169 removeAccountFromCacheLocked(accounts, account);
2170 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2171 .entrySet()) {
2172 if (packageToVisibility.getValue()
2173 != AccountManager.VISIBILITY_NOT_VISIBLE) {
2174 notifyPackage(packageToVisibility.getKey(), accounts);
2175 }
2176 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002177
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002178 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2179 sendAccountsChangedBroadcast(accounts.userId);
2180 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2181 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2182 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2183 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002184 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002185 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002186 long id = Binder.clearCallingIdentity();
2187 try {
2188 int parentUserId = accounts.userId;
2189 if (canHaveProfile(parentUserId)) {
2190 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002191 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002192 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002193 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002194 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002195 }
2196 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002197 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002198 } finally {
2199 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002200 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002201
2202 if (isChanged) {
2203 synchronized (accounts.credentialsPermissionNotificationIds) {
2204 for (Pair<Pair<Account, String>, Integer> key
2205 : accounts.credentialsPermissionNotificationIds.keySet()) {
2206 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002207 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002208 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002209 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002210 account, uid, false));
2211 }
2212 }
2213 }
2214 }
2215
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002216 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002217 }
2218
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002219 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002220 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002221 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002222 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2223 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002224 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2225 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002226 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002227 + ", pid " + Binder.getCallingPid());
2228 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002229 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002230 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002231 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002232 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002233 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002234 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002235 accounts.accountsDb.beginTransaction();
2236 try {
2237 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2238 accounts.accountsDb.setTransactionSuccessful();
2239 } finally {
2240 accounts.accountsDb.endTransaction();
2241 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002242 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002243 for (Pair<Account, String> tokenInfo : deletedTokens) {
2244 Account act = tokenInfo.first;
2245 String tokenType = tokenInfo.second;
2246 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002247 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002248 // wipe out cached token in memory.
2249 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002250 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002251 }
Fred Quintana60307342009-03-24 22:48:12 -07002252 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002253 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002254 }
2255 }
2256
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002257 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002258 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002259 // TODO Move to AccountsDB
2260 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002261 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002262
Fred Quintana33269202009-04-20 16:05:10 -07002263 try {
2264 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002265 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002266 String accountName = cursor.getString(1);
2267 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002268 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002269 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002270 }
Fred Quintana33269202009-04-20 16:05:10 -07002271 } finally {
2272 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002273 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002274 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002275 }
2276
Carlos Valdivia91979be2015-05-22 14:11:35 -07002277 private void saveCachedToken(
2278 UserAccounts accounts,
2279 Account account,
2280 String callerPkg,
2281 byte[] callerSigDigest,
2282 String tokenType,
2283 String token,
2284 long expiryMillis) {
2285
2286 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2287 return;
2288 }
2289 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002290 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002291 synchronized (accounts.cacheLock) {
2292 accounts.accountTokenCaches.put(
2293 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002294 }
2295 }
2296
Amith Yamasani04e0d262012-02-14 11:50:53 -08002297 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2298 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002299 if (account == null || type == null) {
2300 return false;
2301 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002302 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002303 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002304 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002305 accounts.accountsDb.beginTransaction();
2306 boolean updateCache = false;
2307 try {
2308 long accountId = accounts.accountsDb.findDeAccountId(account);
2309 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002310 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002311 }
2312 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2313 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2314 accounts.accountsDb.setTransactionSuccessful();
2315 updateCache = true;
2316 return true;
2317 }
2318 return false;
2319 } finally {
2320 accounts.accountsDb.endTransaction();
2321 if (updateCache) {
2322 synchronized (accounts.cacheLock) {
2323 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2324 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002325 }
Fred Quintana33269202009-04-20 16:05:10 -07002326 }
Fred Quintana60307342009-03-24 22:48:12 -07002327 }
2328 }
2329
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002330 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002331 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002332 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002333 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2334 Log.v(TAG, "peekAuthToken: " + account
2335 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002336 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002337 + ", pid " + Binder.getCallingPid());
2338 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002339 Preconditions.checkNotNull(account, "account cannot be null");
2340 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002341 int userId = UserHandle.getCallingUserId();
2342 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002343 String msg = String.format(
2344 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2345 callingUid,
2346 account.type);
2347 throw new SecurityException(msg);
2348 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002349 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002350 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2351 + callingUid);
2352 return null;
2353 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002354 long identityToken = clearCallingIdentity();
2355 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002356 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002357 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002358 } finally {
2359 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002360 }
Fred Quintana60307342009-03-24 22:48:12 -07002361 }
2362
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002363 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002364 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002365 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002366 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2367 Log.v(TAG, "setAuthToken: " + account
2368 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002369 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002370 + ", pid " + Binder.getCallingPid());
2371 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002372 Preconditions.checkNotNull(account, "account cannot be null");
2373 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002374 int userId = UserHandle.getCallingUserId();
2375 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002376 String msg = String.format(
2377 "uid %s cannot set auth tokens associated with accounts of type: %s",
2378 callingUid,
2379 account.type);
2380 throw new SecurityException(msg);
2381 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002382 long identityToken = clearCallingIdentity();
2383 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002384 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002385 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002386 } finally {
2387 restoreCallingIdentity(identityToken);
2388 }
Fred Quintana60307342009-03-24 22:48:12 -07002389 }
2390
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002391 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002392 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002393 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002394 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2395 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002396 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002397 + ", pid " + Binder.getCallingPid());
2398 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002399 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002400 int userId = UserHandle.getCallingUserId();
2401 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002402 String msg = String.format(
2403 "uid %s cannot set secrets for accounts of type: %s",
2404 callingUid,
2405 account.type);
2406 throw new SecurityException(msg);
2407 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002408 long identityToken = clearCallingIdentity();
2409 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002410 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002411 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002412 } finally {
2413 restoreCallingIdentity(identityToken);
2414 }
Fred Quintana60307342009-03-24 22:48:12 -07002415 }
2416
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002417 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2418 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002419 if (account == null) {
2420 return;
2421 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002422 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002423 synchronized (accounts.dbLock) {
2424 synchronized (accounts.cacheLock) {
2425 accounts.accountsDb.beginTransaction();
2426 try {
2427 final long accountId = accounts.accountsDb.findDeAccountId(account);
2428 if (accountId >= 0) {
2429 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2430 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2431 accounts.authTokenCache.remove(account);
2432 accounts.accountTokenCaches.remove(account);
2433 accounts.accountsDb.setTransactionSuccessful();
2434 // If there is an account whose password will be updated and the database
2435 // transactions succeed, then we say that a change has occured. Even if the
2436 // new password is the same as the old and there were no authtokens to
2437 // delete.
2438 isChanged = true;
2439 String action = (password == null || password.length() == 0) ?
2440 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2441 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2442 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2443 callingUid);
2444 }
2445 } finally {
2446 accounts.accountsDb.endTransaction();
2447 if (isChanged) {
2448 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2449 sendNotificationAccountUpdated(account, accounts);
2450 sendAccountsChangedBroadcast(accounts.userId);
2451 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002452 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002453 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002454 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002455 }
2456
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002457 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002458 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002459 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002460 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2461 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002462 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002463 + ", pid " + Binder.getCallingPid());
2464 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002465 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002466 int userId = UserHandle.getCallingUserId();
2467 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002468 String msg = String.format(
2469 "uid %s cannot clear passwords for accounts of type: %s",
2470 callingUid,
2471 account.type);
2472 throw new SecurityException(msg);
2473 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002474 long identityToken = clearCallingIdentity();
2475 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002476 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002477 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002478 } finally {
2479 restoreCallingIdentity(identityToken);
2480 }
Fred Quintana60307342009-03-24 22:48:12 -07002481 }
2482
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002483 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002484 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002485 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002486 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2487 Log.v(TAG, "setUserData: " + account
2488 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002489 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002490 + ", pid " + Binder.getCallingPid());
2491 }
Fred Quintana382601f2010-03-25 12:25:10 -07002492 if (key == null) throw new IllegalArgumentException("key is null");
2493 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002494 int userId = UserHandle.getCallingUserId();
2495 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002496 String msg = String.format(
2497 "uid %s cannot set user data for accounts of type: %s",
2498 callingUid,
2499 account.type);
2500 throw new SecurityException(msg);
2501 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002502 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002503 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002504 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002505 if (!accountExistsCache(accounts, account)) {
2506 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002507 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002508 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002509 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002510 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002511 }
2512 }
2513
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002514 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2515 synchronized (accounts.cacheLock) {
2516 if (accounts.accountCache.containsKey(account.type)) {
2517 for (Account acc : accounts.accountCache.get(account.type)) {
2518 if (acc.name.equals(account.name)) {
2519 return true;
2520 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002521 }
2522 }
2523 }
2524 return false;
2525 }
2526
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002527 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002528 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002529 synchronized (accounts.dbLock) {
2530 accounts.accountsDb.beginTransaction();
2531 try {
2532 long accountId = accounts.accountsDb.findDeAccountId(account);
2533 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002534 return;
2535 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002536 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2537 if (extrasId < 0) {
2538 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2539 if (extrasId < 0) {
2540 return;
2541 }
2542 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2543 return;
2544 }
2545 accounts.accountsDb.setTransactionSuccessful();
2546 } finally {
2547 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002548 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002549 synchronized (accounts.cacheLock) {
2550 writeUserDataIntoCacheLocked(accounts, account, key, value);
2551 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002552 }
2553 }
2554
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002555 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002556 if (result == null) {
2557 Log.e(TAG, "the result is unexpectedly null", new Exception());
2558 }
2559 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2560 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2561 + response);
2562 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002563 try {
2564 response.onResult(result);
2565 } catch (RemoteException e) {
2566 // if the caller is dead then there is no one to care about remote
2567 // exceptions
2568 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2569 Log.v(TAG, "failure while notifying response", e);
2570 }
2571 }
2572 }
2573
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002574 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002575 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2576 final String authTokenType)
2577 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002578 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2579 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002580
Fred Quintanad9640ec2012-05-23 12:37:00 -07002581 final int callingUid = getCallingUid();
2582 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002583 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002584 throw new SecurityException("can only call from system");
2585 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002586 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002587 long identityToken = clearCallingIdentity();
2588 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002589 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002590 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2591 false /* stripAuthTokenFromResult */, null /* accountName */,
2592 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002593 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002594 protected String toDebugString(long now) {
2595 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002596 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002597 + ", authTokenType " + authTokenType;
2598 }
2599
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002600 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002601 public void run() throws RemoteException {
2602 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2603 }
2604
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002605 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002606 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002607 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002608 if (result != null) {
2609 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2610 Bundle bundle = new Bundle();
2611 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2612 super.onResult(bundle);
2613 return;
2614 } else {
2615 super.onResult(result);
2616 }
2617 }
2618 }.bind();
2619 } finally {
2620 restoreCallingIdentity(identityToken);
2621 }
2622 }
2623
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002624 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002625 public void getAuthToken(
2626 IAccountManagerResponse response,
2627 final Account account,
2628 final String authTokenType,
2629 final boolean notifyOnAuthFailure,
2630 final boolean expectActivityLaunch,
2631 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002632 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002633 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2634 Log.v(TAG, "getAuthToken: " + account
2635 + ", response " + response
2636 + ", authTokenType " + authTokenType
2637 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2638 + ", expectActivityLaunch " + expectActivityLaunch
2639 + ", caller's uid " + Binder.getCallingUid()
2640 + ", pid " + Binder.getCallingPid());
2641 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002642 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002643 try {
2644 if (account == null) {
2645 Slog.w(TAG, "getAuthToken called with null account");
2646 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2647 return;
2648 }
2649 if (authTokenType == null) {
2650 Slog.w(TAG, "getAuthToken called with null authTokenType");
2651 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2652 return;
2653 }
2654 } catch (RemoteException e) {
2655 Slog.w(TAG, "Failed to report error back to the client." + e);
2656 return;
2657 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002658 int userId = UserHandle.getCallingUserId();
2659 long ident = Binder.clearCallingIdentity();
2660 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002661 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002662 try {
2663 accounts = getUserAccounts(userId);
2664 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2665 AuthenticatorDescription.newKey(account.type), accounts.userId);
2666 } finally {
2667 Binder.restoreCallingIdentity(ident);
2668 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002669
Costin Manolachea40c6302010-12-13 14:50:45 -08002670 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002671 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002672
2673 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002674 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002675 final boolean permissionGranted =
2676 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002677
Carlos Valdivia91979be2015-05-22 14:11:35 -07002678 // Get the calling package. We will use it for the purpose of caching.
2679 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002680 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002681 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002682 try {
2683 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2684 } finally {
2685 Binder.restoreCallingIdentity(ident);
2686 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002687 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2688 String msg = String.format(
2689 "Uid %s is attempting to illegally masquerade as package %s!",
2690 callerUid,
2691 callerPkg);
2692 throw new SecurityException(msg);
2693 }
2694
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002695 // let authenticator know the identity of the caller
2696 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2697 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002698
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002699 if (notifyOnAuthFailure) {
2700 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002701 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002702
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002703 long identityToken = clearCallingIdentity();
2704 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002705 // Distill the caller's package signatures into a single digest.
2706 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2707
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002708 // if the caller has permission, do the peek. otherwise go the more expensive
2709 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002710 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002711 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002712 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002713 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002714 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2715 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2716 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002717 onResult(response, result);
2718 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002719 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002720 }
2721
Carlos Valdivia91979be2015-05-22 14:11:35 -07002722 if (customTokens) {
2723 /*
2724 * Look up tokens in the new cache only if the loginOptions don't have parameters
2725 * outside of those expected to be injected by the AccountManager, e.g.
2726 * ANDORID_PACKAGE_NAME.
2727 */
2728 String token = readCachedTokenInternal(
2729 accounts,
2730 account,
2731 authTokenType,
2732 callerPkg,
2733 callerPkgSigDigest);
2734 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002735 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2736 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2737 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002738 Bundle result = new Bundle();
2739 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2740 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2741 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2742 onResult(response, result);
2743 return;
2744 }
2745 }
2746
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002747 new Session(
2748 accounts,
2749 response,
2750 account.type,
2751 expectActivityLaunch,
2752 false /* stripAuthTokenFromResult */,
2753 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002754 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002755 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002756 protected String toDebugString(long now) {
2757 if (loginOptions != null) loginOptions.keySet();
2758 return super.toDebugString(now) + ", getAuthToken"
2759 + ", " + account
2760 + ", authTokenType " + authTokenType
2761 + ", loginOptions " + loginOptions
2762 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2763 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002764
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002765 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002766 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002767 // If the caller doesn't have permission then create and return the
2768 // "grant permission" intent instead of the "getAuthToken" intent.
2769 if (!permissionGranted) {
2770 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2771 } else {
2772 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2773 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002774 }
2775
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002776 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002777 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002778 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002779 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002780 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002781 Intent intent = newGrantCredentialsPermissionIntent(
2782 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002783 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002784 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002785 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002786 authTokenType,
2787 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002788 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002789 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002790 onResult(bundle);
2791 return;
2792 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002793 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002794 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002795 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2796 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002797 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002798 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002799 "the type and name should not be empty");
2800 return;
2801 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002802 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002803 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002804 saveAuthTokenToDatabase(
2805 mAccounts,
2806 resultAccount,
2807 authTokenType,
2808 authToken);
2809 }
2810 long expiryMillis = result.getLong(
2811 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2812 if (customTokens
2813 && expiryMillis > System.currentTimeMillis()) {
2814 saveCachedToken(
2815 mAccounts,
2816 account,
2817 callerPkg,
2818 callerPkgSigDigest,
2819 authTokenType,
2820 authToken,
2821 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002822 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002823 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002824
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002825 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002826 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002827 /*
2828 * Make sure that the supplied intent is owned by the authenticator
2829 * giving it to the system. Otherwise a malicious authenticator could
2830 * have users launching arbitrary activities by tricking users to
2831 * interact with malicious notifications.
2832 */
2833 checkKeyIntent(
2834 Binder.getCallingUid(),
2835 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002836 doNotification(
2837 mAccounts,
2838 account,
2839 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002840 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002841 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002842 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002843 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002844 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002845 }.bind();
2846 } finally {
2847 restoreCallingIdentity(identityToken);
2848 }
Fred Quintana60307342009-03-24 22:48:12 -07002849 }
2850
Carlos Valdivia91979be2015-05-22 14:11:35 -07002851 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2852 MessageDigest digester;
2853 try {
2854 digester = MessageDigest.getInstance("SHA-256");
2855 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2856 callerPkg, PackageManager.GET_SIGNATURES);
2857 for (Signature sig : pkgInfo.signatures) {
2858 digester.update(sig.toByteArray());
2859 }
2860 } catch (NoSuchAlgorithmException x) {
2861 Log.wtf(TAG, "SHA-256 should be available", x);
2862 digester = null;
2863 } catch (NameNotFoundException e) {
2864 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2865 digester = null;
2866 }
2867 return (digester == null) ? null : digester.digest();
2868 }
2869
Dianne Hackborn41203752012-08-31 14:05:51 -07002870 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002871 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002872 int uid = intent.getIntExtra(
2873 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2874 String authTokenType = intent.getStringExtra(
2875 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002876 final String titleAndSubtitle =
2877 mContext.getString(R.string.permission_request_notification_with_subtitle,
2878 account.name);
2879 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002880 String title = titleAndSubtitle;
2881 String subtitle = "";
2882 if (index > 0) {
2883 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002884 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002885 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002886 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002887 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05002888 Notification n =
2889 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
2890 .setSmallIcon(android.R.drawable.stat_sys_warning)
2891 .setWhen(0)
2892 .setColor(contextForUser.getColor(
2893 com.android.internal.R.color.system_notification_accent_color))
2894 .setContentTitle(title)
2895 .setContentText(subtitle)
2896 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2897 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2898 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002899 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002900 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002901 }
2902
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002903 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2904 int uid, AccountAuthenticatorResponse response, String authTokenType,
2905 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002906
2907 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002908
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002909 if (startInNewTask) {
2910 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2911 // Since it was set in Eclair+ we can't change it without breaking apps using
2912 // the intent from a non-Activity context. This is the default behavior.
2913 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2914 }
2915 intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
2916 authTokenType, uid) + (packageName != null ? packageName : "")));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002917 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002918 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2919 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002920 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002921
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002922 return intent;
2923 }
2924
2925 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2926 int uid) {
2927 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002928 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002929 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002930 final Pair<Pair<Account, String>, Integer> key =
2931 new Pair<Pair<Account, String>, Integer>(
2932 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002933 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002934 if (id == null) {
2935 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002936 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002937 }
2938 }
2939 return id;
2940 }
2941
Amith Yamasani04e0d262012-02-14 11:50:53 -08002942 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002943 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002944 synchronized (accounts.signinRequiredNotificationIds) {
2945 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002946 if (id == null) {
2947 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002948 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002949 }
2950 }
2951 return id;
2952 }
2953
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002954 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002955 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002956 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002957 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002958 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002959 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2960 Log.v(TAG, "addAccount: accountType " + accountType
2961 + ", response " + response
2962 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002963 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002964 + ", expectActivityLaunch " + expectActivityLaunch
2965 + ", caller's uid " + Binder.getCallingUid()
2966 + ", pid " + Binder.getCallingPid());
2967 }
Fred Quintana382601f2010-03-25 12:25:10 -07002968 if (response == null) throw new IllegalArgumentException("response is null");
2969 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002970
Amith Yamasani71e6c692013-03-24 17:39:28 -07002971 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002972 final int uid = Binder.getCallingUid();
2973 final int userId = UserHandle.getUserId(uid);
2974 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002975 try {
2976 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2977 "User is not allowed to add an account!");
2978 } catch (RemoteException re) {
2979 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002980 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002981 return;
2982 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002983 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002984 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002985 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2986 "User cannot modify accounts of this type (policy).");
2987 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002988 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002989 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2990 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002991 return;
2992 }
2993
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002994 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002995 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2996 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2997 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2998
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002999 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003000 long identityToken = clearCallingIdentity();
3001 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003002 UserAccounts accounts = getUserAccounts(usrId);
3003 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003004 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3005 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003006 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003007 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003008 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003009 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003010 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003011 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003012 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003013 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003014
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003015 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003016 protected String toDebugString(long now) {
3017 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003018 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003019 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003020 }
3021 }.bind();
3022 } finally {
3023 restoreCallingIdentity(identityToken);
3024 }
Fred Quintana60307342009-03-24 22:48:12 -07003025 }
3026
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003027 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003028 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3029 final String authTokenType, final String[] requiredFeatures,
3030 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003031 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003032 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003033 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3034 Log.v(TAG, "addAccount: accountType " + accountType
3035 + ", response " + response
3036 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003037 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003038 + ", expectActivityLaunch " + expectActivityLaunch
3039 + ", caller's uid " + Binder.getCallingUid()
3040 + ", pid " + Binder.getCallingPid()
3041 + ", for user id " + userId);
3042 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003043 Preconditions.checkArgument(response != null, "response cannot be null");
3044 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003045 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003046 if (isCrossUser(callingUid, userId)) {
3047 throw new SecurityException(
3048 String.format(
3049 "User %s trying to add account for %s" ,
3050 UserHandle.getCallingUserId(),
3051 userId));
3052 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003053
3054 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003055 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003056 try {
3057 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3058 "User is not allowed to add an account!");
3059 } catch (RemoteException re) {
3060 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003061 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003062 return;
3063 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003064 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003065 try {
3066 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3067 "User cannot modify accounts of this type (policy).");
3068 } catch (RemoteException re) {
3069 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003070 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3071 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003072 return;
3073 }
3074
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003075 final int pid = Binder.getCallingPid();
3076 final int uid = Binder.getCallingUid();
3077 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3078 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3079 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3080
3081 long identityToken = clearCallingIdentity();
3082 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003083 UserAccounts accounts = getUserAccounts(userId);
3084 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003085 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3086 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003087 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003088 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003089 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003090 @Override
3091 public void run() throws RemoteException {
3092 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3093 options);
3094 }
3095
3096 @Override
3097 protected String toDebugString(long now) {
3098 return super.toDebugString(now) + ", addAccount"
3099 + ", accountType " + accountType
3100 + ", requiredFeatures "
3101 + (requiredFeatures != null
3102 ? TextUtils.join(",", requiredFeatures)
3103 : null);
3104 }
3105 }.bind();
3106 } finally {
3107 restoreCallingIdentity(identityToken);
3108 }
3109 }
3110
Sandra Kwan78812282015-11-04 11:19:47 -08003111 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003112 public void startAddAccountSession(
3113 final IAccountManagerResponse response,
3114 final String accountType,
3115 final String authTokenType,
3116 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003117 final boolean expectActivityLaunch,
3118 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003119 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003120 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3121 Log.v(TAG,
3122 "startAddAccountSession: accountType " + accountType
3123 + ", response " + response
3124 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003125 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003126 + ", expectActivityLaunch " + expectActivityLaunch
3127 + ", caller's uid " + Binder.getCallingUid()
3128 + ", pid " + Binder.getCallingPid());
3129 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003130 Preconditions.checkArgument(response != null, "response cannot be null");
3131 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003132
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003133 final int uid = Binder.getCallingUid();
3134 final int userId = UserHandle.getUserId(uid);
3135 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003136 try {
3137 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3138 "User is not allowed to add an account!");
3139 } catch (RemoteException re) {
3140 }
3141 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3142 return;
3143 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003144 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003145 try {
3146 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3147 "User cannot modify accounts of this type (policy).");
3148 } catch (RemoteException re) {
3149 }
3150 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3151 userId);
3152 return;
3153 }
Sandra Kwan78812282015-11-04 11:19:47 -08003154 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003155 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3156 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3157 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3158
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003159 // Check to see if the Password should be included to the caller.
3160 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3161 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003162 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003163
Sandra Kwan78812282015-11-04 11:19:47 -08003164 long identityToken = clearCallingIdentity();
3165 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003166 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003167 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3168 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003169 new StartAccountSession(
3170 accounts,
3171 response,
3172 accountType,
3173 expectActivityLaunch,
3174 null /* accountName */,
3175 false /* authDetailsRequired */,
3176 true /* updateLastAuthenticationTime */,
3177 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003178 @Override
3179 public void run() throws RemoteException {
3180 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3181 requiredFeatures, options);
3182 }
3183
3184 @Override
3185 protected String toDebugString(long now) {
3186 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3187 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3188 + accountType + ", requiredFeatures "
3189 + (requiredFeatures != null ? requiredFeaturesStr : null);
3190 }
3191 }.bind();
3192 } finally {
3193 restoreCallingIdentity(identityToken);
3194 }
3195 }
3196
3197 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3198 private abstract class StartAccountSession extends Session {
3199
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003200 private final boolean mIsPasswordForwardingAllowed;
3201
3202 public StartAccountSession(
3203 UserAccounts accounts,
3204 IAccountManagerResponse response,
3205 String accountType,
3206 boolean expectActivityLaunch,
3207 String accountName,
3208 boolean authDetailsRequired,
3209 boolean updateLastAuthenticationTime,
3210 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003211 super(accounts, response, accountType, expectActivityLaunch,
3212 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3213 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003214 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003215 }
3216
3217 @Override
3218 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003219 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003220 mNumResults++;
3221 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003222 if (result != null
3223 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003224 checkKeyIntent(
3225 Binder.getCallingUid(),
3226 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003227 }
Sandra Kwan78812282015-11-04 11:19:47 -08003228 IAccountManagerResponse response;
3229 if (mExpectActivityLaunch && result != null
3230 && result.containsKey(AccountManager.KEY_INTENT)) {
3231 response = mResponse;
3232 } else {
3233 response = getResponseAndClose();
3234 }
3235 if (response == null) {
3236 return;
3237 }
3238 if (result == null) {
3239 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3240 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3241 + response);
3242 }
3243 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3244 "null bundle returned");
3245 return;
3246 }
3247
3248 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3249 // All AccountManager error codes are greater
3250 // than 0
3251 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3252 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3253 return;
3254 }
3255
Hongming Jin368aa192016-07-29 14:29:54 -07003256 // Omit passwords if the caller isn't permitted to see them.
3257 if (!mIsPasswordForwardingAllowed) {
3258 result.remove(AccountManager.KEY_PASSWORD);
3259 }
3260
Sandra Kwan78812282015-11-04 11:19:47 -08003261 // Strip auth token from result.
3262 result.remove(AccountManager.KEY_AUTHTOKEN);
3263
3264 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3265 Log.v(TAG,
3266 getClass().getSimpleName() + " calling onResult() on response " + response);
3267 }
3268
3269 // Get the session bundle created by authenticator. The
3270 // bundle contains data necessary for finishing the session
3271 // later. The session bundle will be encrypted here and
3272 // decrypted later when trying to finish the session.
3273 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3274 if (sessionBundle != null) {
3275 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3276 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003277 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003278 Log.w(TAG, "Account type in session bundle doesn't match request.");
3279 }
3280 // Add accountType info to session bundle. This will
3281 // override any value set by authenticator.
3282 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3283
3284 // Encrypt session bundle before returning to caller.
3285 try {
3286 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3287 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3288 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3289 } catch (GeneralSecurityException e) {
3290 if (Log.isLoggable(TAG, Log.DEBUG)) {
3291 Log.v(TAG, "Failed to encrypt session bundle!", e);
3292 }
3293 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3294 "failed to encrypt session bundle");
3295 return;
3296 }
3297 }
3298
3299 sendResponse(response, result);
3300 }
3301 }
3302
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003303 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003304 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003305 @NonNull Bundle sessionBundle,
3306 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003307 Bundle appInfo,
3308 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003309 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003310 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003311 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3312 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003313 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003314 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003315 + ", caller's uid " + callingUid
3316 + ", caller's user id " + UserHandle.getCallingUserId()
3317 + ", pid " + Binder.getCallingPid()
3318 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003319 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003320 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003321 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3322 // Account type is added to it before encryption.
3323 if (sessionBundle == null || sessionBundle.size() == 0) {
3324 throw new IllegalArgumentException("sessionBundle is empty");
3325 }
3326
Dmitry Dementyev52745472016-12-02 10:27:45 -08003327 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003328 if (isCrossUser(callingUid, userId)) {
3329 throw new SecurityException(
3330 String.format(
3331 "User %s trying to finish session for %s without cross user permission",
3332 UserHandle.getCallingUserId(),
3333 userId));
3334 }
3335
Sandra Kwan0b84b452016-01-20 15:25:42 -08003336 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003337 sendErrorResponse(response,
3338 AccountManager.ERROR_CODE_USER_RESTRICTED,
3339 "User is not allowed to add an account!");
3340 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3341 return;
3342 }
3343
3344 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003345 final Bundle decryptedBundle;
3346 final String accountType;
3347 // First decrypt session bundle to get account type for checking permission.
3348 try {
3349 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3350 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3351 if (decryptedBundle == null) {
3352 sendErrorResponse(
3353 response,
3354 AccountManager.ERROR_CODE_BAD_REQUEST,
3355 "failed to decrypt session bundle");
3356 return;
3357 }
3358 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3359 // Account type cannot be null. This should not happen if session bundle was created
3360 // properly by #StartAccountSession.
3361 if (TextUtils.isEmpty(accountType)) {
3362 sendErrorResponse(
3363 response,
3364 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3365 "accountType is empty");
3366 return;
3367 }
3368
3369 // If by any chances, decryptedBundle contains colliding keys with
3370 // system info
3371 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3372 // update credentials flow, we should replace with the new values of the current call.
3373 if (appInfo != null) {
3374 decryptedBundle.putAll(appInfo);
3375 }
3376
3377 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003378 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003379 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3380 } catch (GeneralSecurityException e) {
3381 if (Log.isLoggable(TAG, Log.DEBUG)) {
3382 Log.v(TAG, "Failed to decrypt session bundle!", e);
3383 }
3384 sendErrorResponse(
3385 response,
3386 AccountManager.ERROR_CODE_BAD_REQUEST,
3387 "failed to decrypt session bundle");
3388 return;
3389 }
3390
Sandra Kwan0b84b452016-01-20 15:25:42 -08003391 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003392 sendErrorResponse(
3393 response,
3394 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3395 "User cannot modify accounts of this type (policy).");
3396 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3397 userId);
3398 return;
3399 }
3400
3401 long identityToken = clearCallingIdentity();
3402 try {
3403 UserAccounts accounts = getUserAccounts(userId);
3404 logRecordWithUid(
3405 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003406 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3407 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003408 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003409 new Session(
3410 accounts,
3411 response,
3412 accountType,
3413 expectActivityLaunch,
3414 true /* stripAuthTokenFromResult */,
3415 null /* accountName */,
3416 false /* authDetailsRequired */,
3417 true /* updateLastAuthenticationTime */) {
3418 @Override
3419 public void run() throws RemoteException {
3420 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3421 }
3422
3423 @Override
3424 protected String toDebugString(long now) {
3425 return super.toDebugString(now)
3426 + ", finishSession"
3427 + ", accountType " + accountType;
3428 }
3429 }.bind();
3430 } finally {
3431 restoreCallingIdentity(identityToken);
3432 }
3433 }
3434
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003435 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003436 final DevicePolicyManagerInternal dpmi =
3437 LocalServices.getService(DevicePolicyManagerInternal.class);
3438 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003439 if (dpmi == null) {
3440 intent = getDefaultCantAddAccountIntent(errorCode);
3441 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003442 intent = dpmi.createUserRestrictionSupportIntent(userId,
3443 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3444 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3445 intent = dpmi.createShowAdminSupportIntent(userId, false);
3446 }
3447 if (intent == null) {
3448 intent = getDefaultCantAddAccountIntent(errorCode);
3449 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003450 long identityToken = clearCallingIdentity();
3451 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003452 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003453 } finally {
3454 restoreCallingIdentity(identityToken);
3455 }
3456 }
3457
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003458 /**
3459 * Called when we don't know precisely who is preventing us from adding an account.
3460 */
3461 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3462 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3463 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3464 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3465 return cantAddAccount;
3466 }
3467
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003468 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003469 public void confirmCredentialsAsUser(
3470 IAccountManagerResponse response,
3471 final Account account,
3472 final Bundle options,
3473 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003474 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003475 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003476 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003477 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3478 Log.v(TAG, "confirmCredentials: " + account
3479 + ", response " + response
3480 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003481 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003482 + ", pid " + Binder.getCallingPid());
3483 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003484 // Only allow the system process to read accounts of other users
3485 if (isCrossUser(callingUid, userId)) {
3486 throw new SecurityException(
3487 String.format(
3488 "User %s trying to confirm account credentials for %s" ,
3489 UserHandle.getCallingUserId(),
3490 userId));
3491 }
Fred Quintana382601f2010-03-25 12:25:10 -07003492 if (response == null) throw new IllegalArgumentException("response is null");
3493 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003494 long identityToken = clearCallingIdentity();
3495 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003496 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003497 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003498 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003499 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003500 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003501 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003502 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003503 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003504 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003505 protected String toDebugString(long now) {
3506 return super.toDebugString(now) + ", confirmCredentials"
3507 + ", " + account;
3508 }
3509 }.bind();
3510 } finally {
3511 restoreCallingIdentity(identityToken);
3512 }
Fred Quintana60307342009-03-24 22:48:12 -07003513 }
3514
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003515 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003516 public void updateCredentials(IAccountManagerResponse response, final Account account,
3517 final String authTokenType, final boolean expectActivityLaunch,
3518 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003519 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003520 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3521 Log.v(TAG, "updateCredentials: " + account
3522 + ", response " + response
3523 + ", authTokenType " + authTokenType
3524 + ", expectActivityLaunch " + expectActivityLaunch
3525 + ", caller's uid " + Binder.getCallingUid()
3526 + ", pid " + Binder.getCallingPid());
3527 }
Fred Quintana382601f2010-03-25 12:25:10 -07003528 if (response == null) throw new IllegalArgumentException("response is null");
3529 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003530 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003531 long identityToken = clearCallingIdentity();
3532 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003533 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003534 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003535 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003536 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003537 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003538 public void run() throws RemoteException {
3539 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3540 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003541 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003542 protected String toDebugString(long now) {
3543 if (loginOptions != null) loginOptions.keySet();
3544 return super.toDebugString(now) + ", updateCredentials"
3545 + ", " + account
3546 + ", authTokenType " + authTokenType
3547 + ", loginOptions " + loginOptions;
3548 }
3549 }.bind();
3550 } finally {
3551 restoreCallingIdentity(identityToken);
3552 }
Fred Quintana60307342009-03-24 22:48:12 -07003553 }
3554
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003555 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003556 public void startUpdateCredentialsSession(
3557 IAccountManagerResponse response,
3558 final Account account,
3559 final String authTokenType,
3560 final boolean expectActivityLaunch,
3561 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003562 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003563 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3564 Log.v(TAG,
3565 "startUpdateCredentialsSession: " + account + ", response " + response
3566 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3567 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3568 + ", pid " + Binder.getCallingPid());
3569 }
3570 if (response == null) {
3571 throw new IllegalArgumentException("response is null");
3572 }
3573 if (account == null) {
3574 throw new IllegalArgumentException("account is null");
3575 }
Sandra Kwana578d112015-12-16 16:01:43 -08003576
3577 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003578 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003579
3580 // Check to see if the Password should be included to the caller.
3581 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3582 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003583 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003584
Sandra Kwane68c37e2015-11-12 17:11:49 -08003585 long identityToken = clearCallingIdentity();
3586 try {
3587 UserAccounts accounts = getUserAccounts(userId);
3588 new StartAccountSession(
3589 accounts,
3590 response,
3591 account.type,
3592 expectActivityLaunch,
3593 account.name,
3594 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003595 true /* updateLastCredentialTime */,
3596 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003597 @Override
3598 public void run() throws RemoteException {
3599 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3600 loginOptions);
3601 }
3602
3603 @Override
3604 protected String toDebugString(long now) {
3605 if (loginOptions != null)
3606 loginOptions.keySet();
3607 return super.toDebugString(now)
3608 + ", startUpdateCredentialsSession"
3609 + ", " + account
3610 + ", authTokenType " + authTokenType
3611 + ", loginOptions " + loginOptions;
3612 }
3613 }.bind();
3614 } finally {
3615 restoreCallingIdentity(identityToken);
3616 }
3617 }
3618
3619 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003620 public void isCredentialsUpdateSuggested(
3621 IAccountManagerResponse response,
3622 final Account account,
3623 final String statusToken) {
3624 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3625 Log.v(TAG,
3626 "isCredentialsUpdateSuggested: " + account + ", response " + response
3627 + ", caller's uid " + Binder.getCallingUid()
3628 + ", pid " + Binder.getCallingPid());
3629 }
3630 if (response == null) {
3631 throw new IllegalArgumentException("response is null");
3632 }
3633 if (account == null) {
3634 throw new IllegalArgumentException("account is null");
3635 }
3636 if (TextUtils.isEmpty(statusToken)) {
3637 throw new IllegalArgumentException("status token is empty");
3638 }
3639
Sandra Kwan390c9d22016-01-12 14:13:37 -08003640 int usrId = UserHandle.getCallingUserId();
3641 long identityToken = clearCallingIdentity();
3642 try {
3643 UserAccounts accounts = getUserAccounts(usrId);
3644 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3645 false /* stripAuthTokenFromResult */, account.name,
3646 false /* authDetailsRequired */) {
3647 @Override
3648 protected String toDebugString(long now) {
3649 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3650 + ", " + account;
3651 }
3652
3653 @Override
3654 public void run() throws RemoteException {
3655 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3656 }
3657
3658 @Override
3659 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003660 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003661 IAccountManagerResponse response = getResponseAndClose();
3662 if (response == null) {
3663 return;
3664 }
3665
3666 if (result == null) {
3667 sendErrorResponse(
3668 response,
3669 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3670 "null bundle");
3671 return;
3672 }
3673
3674 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3675 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3676 + response);
3677 }
3678 // Check to see if an error occurred. We know if an error occurred because all
3679 // error codes are greater than 0.
3680 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3681 sendErrorResponse(response,
3682 result.getInt(AccountManager.KEY_ERROR_CODE),
3683 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3684 return;
3685 }
3686 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3687 sendErrorResponse(
3688 response,
3689 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3690 "no result in response");
3691 return;
3692 }
3693 final Bundle newResult = new Bundle();
3694 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3695 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3696 sendResponse(response, newResult);
3697 }
3698 }.bind();
3699 } finally {
3700 restoreCallingIdentity(identityToken);
3701 }
3702 }
3703
3704 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003705 public void editProperties(IAccountManagerResponse response, final String accountType,
3706 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003707 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003708 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3709 Log.v(TAG, "editProperties: accountType " + accountType
3710 + ", response " + response
3711 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003712 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003713 + ", pid " + Binder.getCallingPid());
3714 }
Fred Quintana382601f2010-03-25 12:25:10 -07003715 if (response == null) throw new IllegalArgumentException("response is null");
3716 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003717 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003718 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3719 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003720 String msg = String.format(
3721 "uid %s cannot edit authenticator properites for account type: %s",
3722 callingUid,
3723 accountType);
3724 throw new SecurityException(msg);
3725 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003726 long identityToken = clearCallingIdentity();
3727 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003728 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003729 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003730 true /* stripAuthTokenFromResult */, null /* accountName */,
3731 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003732 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003733 public void run() throws RemoteException {
3734 mAuthenticator.editProperties(this, mAccountType);
3735 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003736 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003737 protected String toDebugString(long now) {
3738 return super.toDebugString(now) + ", editProperties"
3739 + ", accountType " + accountType;
3740 }
3741 }.bind();
3742 } finally {
3743 restoreCallingIdentity(identityToken);
3744 }
Fred Quintana60307342009-03-24 22:48:12 -07003745 }
3746
Amith Yamasani12747872015-12-07 14:19:49 -08003747 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003748 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3749 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003750 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003751 throw new SecurityException("Can be called only by system UID");
3752 }
3753 Preconditions.checkNotNull(account, "account cannot be null");
3754 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3755 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3756
3757 final int userId = userHandle.getIdentifier();
3758
3759 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3760
3761 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003762 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003763 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003764 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003765 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003766 return false;
3767 }
3768 }
3769
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003770 // Returns package with oldest target SDK for given UID.
3771 private String getPackageNameForUid(int uid) {
3772 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3773 if (ArrayUtils.isEmpty(packageNames)) {
3774 return null;
3775 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003776 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003777 if (packageNames.length == 1) {
3778 return packageName;
3779 }
3780 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003781 int oldestVersion = Integer.MAX_VALUE;
3782 for (String name : packageNames) {
3783 try {
3784 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3785 if (applicationInfo != null) {
3786 int version = applicationInfo.targetSdkVersion;
3787 if (version < oldestVersion) {
3788 oldestVersion = version;
3789 packageName = name;
3790 }
3791 }
3792 } catch (NameNotFoundException e) {
3793 // skip
3794 }
3795 }
3796 return packageName;
3797 }
3798
Svet Ganovf6d424f12016-09-20 20:18:53 -07003799 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3800 int uid) {
3801 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003802 packageName = getPackageNameForUid(uid);
3803 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003804 return false;
3805 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003806 }
3807
3808 // Use null token which means any token. Having a token means the package
3809 // is trusted by the authenticator, hence it is fine to access the account.
3810 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3811 return true;
3812 }
3813 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003814 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003815
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003816 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003817 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003818 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003819 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003820 }
3821
3822 @Override
3823 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3824 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003825 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003826 throw new SecurityException("Can be called only by system UID");
3827 }
3828
3829 Preconditions.checkNotNull(account, "account cannot be null");
3830 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3831 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3832
3833 final int userId = userHandle.getIdentifier();
3834
3835 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3836
3837 final int uid;
3838 try {
3839 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3840 } catch (NameNotFoundException e) {
3841 Slog.e(TAG, "Unknown package " + packageName);
3842 return null;
3843 }
3844
3845 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3846
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003847 final long identity = Binder.clearCallingIdentity();
3848 try {
3849 return PendingIntent.getActivityAsUser(
3850 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3851 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3852 null, new UserHandle(userId)).getIntentSender();
3853 } finally {
3854 Binder.restoreCallingIdentity(identity);
3855 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003856 }
3857
3858 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3859 int uid, RemoteCallback callback) {
3860 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3861 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3862 @Override
3863 public void onResult(Bundle value) throws RemoteException {
3864 handleAuthenticatorResponse(true);
3865 }
3866
3867 @Override
3868 public void onRequestContinued() {
3869 /* ignore */
3870 }
3871
3872 @Override
3873 public void onError(int errorCode, String errorMessage) throws RemoteException {
3874 handleAuthenticatorResponse(false);
3875 }
3876
3877 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3878 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003879 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003880 UserHandle.getUserHandleForUid(uid));
3881 if (callback != null) {
3882 Bundle result = new Bundle();
3883 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3884 callback.sendResult(result);
3885 }
3886 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003887 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003888 }
3889
3890 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003891 public boolean someUserHasAccount(@NonNull final Account account) {
3892 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3893 throw new SecurityException("Only system can check for accounts across users");
3894 }
3895 final long token = Binder.clearCallingIdentity();
3896 try {
3897 AccountAndUser[] allAccounts = getAllAccounts();
3898 for (int i = allAccounts.length - 1; i >= 0; i--) {
3899 if (allAccounts[i].account.equals(account)) {
3900 return true;
3901 }
3902 }
3903 return false;
3904 } finally {
3905 Binder.restoreCallingIdentity(token);
3906 }
3907 }
3908
Fred Quintana33269202009-04-20 16:05:10 -07003909 private class GetAccountsByTypeAndFeatureSession extends Session {
3910 private final String[] mFeatures;
3911 private volatile Account[] mAccountsOfType = null;
3912 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3913 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003914 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003915 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003916
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003917 public GetAccountsByTypeAndFeatureSession(
3918 UserAccounts accounts,
3919 IAccountManagerResponse response,
3920 String type,
3921 String[] features,
3922 int callingUid,
3923 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003924 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003925 true /* stripAuthTokenFromResult */, null /* accountName */,
3926 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003927 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003928 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003929 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003930 }
3931
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003932 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003933 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07003934 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
3935 mCallingUid, mPackageName, false /* include managed not visible*/);
Fred Quintana33269202009-04-20 16:05:10 -07003936 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003937 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003938 mCurrentAccount = 0;
3939
3940 checkAccount();
3941 }
3942
3943 public void checkAccount() {
3944 if (mCurrentAccount >= mAccountsOfType.length) {
3945 sendResult();
3946 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003947 }
Fred Quintana33269202009-04-20 16:05:10 -07003948
Fred Quintana29e94b82010-03-10 12:11:51 -08003949 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3950 if (accountAuthenticator == null) {
3951 // It is possible that the authenticator has died, which is indicated by
3952 // mAuthenticator being set to null. If this happens then just abort.
3953 // There is no need to send back a result or error in this case since
3954 // that already happened when mAuthenticator was cleared.
3955 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3956 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3957 + " connected to the authenticator, " + toDebugString());
3958 }
3959 return;
3960 }
Fred Quintana33269202009-04-20 16:05:10 -07003961 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003962 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003963 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003964 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003965 }
3966 }
3967
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003968 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003969 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003970 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003971 mNumResults++;
3972 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003973 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003974 return;
3975 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003976 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003977 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3978 }
3979 mCurrentAccount++;
3980 checkAccount();
3981 }
3982
3983 public void sendResult() {
3984 IAccountManagerResponse response = getResponseAndClose();
3985 if (response != null) {
3986 try {
3987 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3988 for (int i = 0; i < accounts.length; i++) {
3989 accounts[i] = mAccountsWithFeatures.get(i);
3990 }
Fred Quintana56285a62010-12-02 14:20:51 -08003991 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3992 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3993 + response);
3994 }
Fred Quintana33269202009-04-20 16:05:10 -07003995 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003996 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07003997 response.onResult(result);
3998 } catch (RemoteException e) {
3999 // if the caller is dead then there is no one to care about remote exceptions
4000 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4001 Log.v(TAG, "failure while notifying response", e);
4002 }
4003 }
4004 }
4005 }
4006
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004007 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004008 protected String toDebugString(long now) {
4009 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4010 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4011 }
4012 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004013
Amith Yamasani04e0d262012-02-14 11:50:53 -08004014 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004015 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004016 * @hide
4017 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004018 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004019 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004020 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004021 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004022 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4023 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004024 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004025 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004026 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004027 long identityToken = clearCallingIdentity();
4028 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004029 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004030 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004031 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004032 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004033 opPackageName,
4034 visibleAccountTypes,
4035 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004036 } finally {
4037 restoreCallingIdentity(identityToken);
4038 }
4039 }
4040
Amith Yamasanif29f2362012-04-05 18:29:52 -07004041 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004042 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004043 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004044 * @hide
4045 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004046 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004047 public AccountAndUser[] getRunningAccounts() {
4048 final int[] runningUserIds;
4049 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004050 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004051 } catch (RemoteException e) {
4052 // Running in system_server; should never happen
4053 throw new RuntimeException(e);
4054 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004055 return getAccounts(runningUserIds);
4056 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004057
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004058 /**
4059 * Returns accounts for all users, ignores visibility values.
4060 *
4061 * @hide
4062 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004063 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004064 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004065 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004066 final int[] userIds = new int[users.size()];
4067 for (int i = 0; i < userIds.length; i++) {
4068 userIds[i] = users.get(i).id;
4069 }
4070 return getAccounts(userIds);
4071 }
4072
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004073 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004074 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004075 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004076 for (int userId : userIds) {
4077 UserAccounts userAccounts = getUserAccounts(userId);
4078 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004079 Account[] accounts = getAccountsFromCache(
4080 userAccounts,
4081 null /* type */,
4082 Binder.getCallingUid(),
4083 null /* packageName */,
4084 false /* include managed not visible*/);
4085 for (Account account : accounts) {
4086 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004087 }
4088 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004089
4090 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4091 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004092 }
4093
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004094 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004095 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004096 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004097 int callingUid = Binder.getCallingUid();
4098 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004099 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004100 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004101 }
4102
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004103 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004104 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004105 String type,
4106 int userId,
4107 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004108 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004109 String opPackageName,
4110 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004111 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004112 // Only allow the system process to read accounts of other users
4113 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004114 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004115 && mContext.checkCallingOrSelfPermission(
4116 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4117 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004118 throw new SecurityException("User " + UserHandle.getCallingUserId()
4119 + " trying to get account for " + userId);
4120 }
4121
Fred Quintana56285a62010-12-02 14:20:51 -08004122 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4123 Log.v(TAG, "getAccounts: accountType " + type
4124 + ", caller's uid " + Binder.getCallingUid()
4125 + ", pid " + Binder.getCallingPid());
4126 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004127
4128 // If the original calling app was using account choosing activity
4129 // provided by the framework or authenticator we'll passing in
4130 // the original caller's uid here, which is what should be used for filtering.
4131 List<String> managedTypes =
4132 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4133 if (packageUid != -1 &&
4134 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4135 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004136 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004137 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004138 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004139 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4140 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004141 if (visibleAccountTypes.isEmpty()
4142 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004143 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004144 } else if (visibleAccountTypes.contains(type)) {
4145 // Prune the list down to just the requested type.
4146 visibleAccountTypes = new ArrayList<>();
4147 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004148 } // else aggregate all the visible accounts (it won't matter if the
4149 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004150
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004151 long identityToken = clearCallingIdentity();
4152 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004153 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004154 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004155 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004156 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004157 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004158 visibleAccountTypes,
4159 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004160 } finally {
4161 restoreCallingIdentity(identityToken);
4162 }
4163 }
4164
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004165 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004166 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004167 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004168 int callingUid,
4169 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004170 List<String> visibleAccountTypes,
4171 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004172 ArrayList<Account> visibleAccounts = new ArrayList<>();
4173 for (String visibleType : visibleAccountTypes) {
4174 Account[] accountsForType = getAccountsFromCache(
4175 userAccounts, visibleType, callingUid, callingPackage,
4176 includeUserManagedNotVisible);
4177 if (accountsForType != null) {
4178 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004179 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004180 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004181 Account[] result = new Account[visibleAccounts.size()];
4182 for (int i = 0; i < visibleAccounts.size(); i++) {
4183 result[i] = visibleAccounts.get(i);
4184 }
4185 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004186 }
4187
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004188 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004189 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4190 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004191 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004192 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004193 for (Account account : accounts) {
4194 addSharedAccountAsUser(account, userId);
4195 }
4196 }
4197
4198 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004199 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004200 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004201 accounts.accountsDb.deleteSharedAccount(account);
4202 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004203 if (accountId < 0) {
4204 Log.w(TAG, "insertAccountIntoDatabase: " + account
4205 + ", skipping the DB insert failed");
4206 return false;
4207 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004208 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4209 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004210 return true;
4211 }
4212
4213 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004214 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4215 userId = handleIncomingUser(userId);
4216 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004217 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4218 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004219 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004220 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004221 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004222 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004223 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004224 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004225 }
4226 return r > 0;
4227 }
4228
4229 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004230 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004231 return removeSharedAccountAsUser(account, userId, getCallingUid());
4232 }
4233
4234 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004235 userId = handleIncomingUser(userId);
4236 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004237 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4238 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004239 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004240 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004241 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004242 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004243 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004244 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004245 }
4246
4247 @Override
4248 public Account[] getSharedAccountsAsUser(int userId) {
4249 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004250 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004251 synchronized (accounts.dbLock) {
4252 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4253 Account[] accountArray = new Account[accountList.size()];
4254 accountList.toArray(accountArray);
4255 return accountArray;
4256 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004257 }
4258
4259 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004260 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004261 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004262 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004263 }
4264
Amith Yamasani27db4682013-03-30 17:07:47 -07004265 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004266 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004267 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004268 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004269 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004270 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004271 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4272 + callingUid + " with uid=" + uid);
4273 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004274 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004275 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004276 }
4277
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004278 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004279 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004280 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4281 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004282 int callingUid = Binder.getCallingUid();
4283 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004284 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004285 int packageUid = -1;
4286 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004287 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4288 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004289 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004290 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004291 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004292 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004293 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4294 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004295 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004296 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004297 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004298 }
4299
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004300 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004301 public void getAccountsByFeatures(
4302 IAccountManagerResponse response,
4303 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004304 String[] features,
4305 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004306 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004307 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004308 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4309 Log.v(TAG, "getAccounts: accountType " + type
4310 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004311 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004312 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004313 + ", pid " + Binder.getCallingPid());
4314 }
Fred Quintana382601f2010-03-25 12:25:10 -07004315 if (response == null) throw new IllegalArgumentException("response is null");
4316 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004317 int userId = UserHandle.getCallingUserId();
4318
Svetoslavf3f02ac2015-09-08 14:36:35 -07004319 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4320 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004321 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004322 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004323 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004324 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004325 try {
4326 response.onResult(result);
4327 } catch (RemoteException e) {
4328 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4329 }
4330 return;
4331 }
Fred Quintana33269202009-04-20 16:05:10 -07004332 long identityToken = clearCallingIdentity();
4333 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004334 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004335 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004336 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4337 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004338 Bundle result = new Bundle();
4339 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4340 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004341 return;
4342 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004343 new GetAccountsByTypeAndFeatureSession(
4344 userAccounts,
4345 response,
4346 type,
4347 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004348 callingUid,
4349 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004350 } finally {
4351 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004352 }
4353 }
4354
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004355 @Override
4356 public void onAccountAccessed(String token) throws RemoteException {
4357 final int uid = Binder.getCallingUid();
4358 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4359 return;
4360 }
4361 final int userId = UserHandle.getCallingUserId();
4362 final long identity = Binder.clearCallingIdentity();
4363 try {
4364 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4365 if (Objects.equals(account.getAccessId(), token)) {
4366 // An app just accessed the account. At this point it knows about
4367 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004368 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004369 if (!hasAccountAccess(account, null, uid)) {
4370 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4371 uid, true);
4372 }
4373 }
4374 }
4375 } finally {
4376 Binder.restoreCallingIdentity(identity);
4377 }
4378 }
4379
Fred Quintanaa698f422009-04-08 19:14:54 -07004380 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004381 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004382 IAccountManagerResponse mResponse;
4383 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004384 final boolean mExpectActivityLaunch;
4385 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004386 final String mAccountName;
4387 // Indicates if we need to add auth details(like last credential time)
4388 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004389 // If set, we need to update the last authenticated time. This is
4390 // currently
4391 // used on
4392 // successful confirming credentials.
4393 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004394
Fred Quintana33269202009-04-20 16:05:10 -07004395 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004396 private int mNumRequestContinued = 0;
4397 private int mNumErrors = 0;
4398
Fred Quintana60307342009-03-24 22:48:12 -07004399 IAccountAuthenticator mAuthenticator = null;
4400
Fred Quintana8570f742010-02-18 10:32:54 -08004401 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004402 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004403
Amith Yamasani04e0d262012-02-14 11:50:53 -08004404 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004405 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4406 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004407 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4408 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4409 }
4410
4411 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4412 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4413 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004414 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004415 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004416 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004417 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004418 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004419 mResponse = response;
4420 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004421 mExpectActivityLaunch = expectActivityLaunch;
4422 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004423 mAccountName = accountName;
4424 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004425 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004426
Fred Quintanaa698f422009-04-08 19:14:54 -07004427 synchronized (mSessions) {
4428 mSessions.put(toString(), this);
4429 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004430 if (response != null) {
4431 try {
4432 response.asBinder().linkToDeath(this, 0 /* flags */);
4433 } catch (RemoteException e) {
4434 mResponse = null;
4435 binderDied();
4436 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004437 }
Fred Quintana60307342009-03-24 22:48:12 -07004438 }
4439
Fred Quintanaa698f422009-04-08 19:14:54 -07004440 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004441 if (mResponse == null) {
4442 // this session has already been closed
4443 return null;
4444 }
Fred Quintana60307342009-03-24 22:48:12 -07004445 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004446 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004447 return response;
4448 }
4449
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004450 /**
4451 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4452 * security policy.
4453 *
4454 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004455 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004456 * supplied entries in the system Settings app.
4457 */
4458 protected void checkKeyIntent(
4459 int authUid,
4460 Intent intent) throws SecurityException {
4461 long bid = Binder.clearCallingIdentity();
4462 try {
4463 PackageManager pm = mContext.getPackageManager();
4464 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4465 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4466 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004467 if (!isExportedSystemActivity(targetActivityInfo)
4468 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4469 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004470 String pkgName = targetActivityInfo.packageName;
4471 String activityName = targetActivityInfo.name;
4472 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4473 + "does not share a signature with the supplying authenticator (%s).";
4474 throw new SecurityException(
4475 String.format(tmpl, activityName, pkgName, mAccountType));
4476 }
4477 } finally {
4478 Binder.restoreCallingIdentity(bid);
4479 }
4480 }
4481
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004482 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4483 String className = activityInfo.name;
4484 return "android".equals(activityInfo.packageName) &&
4485 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4486 || CantAddAccountActivity.class.getName().equals(className));
4487 }
4488
Fred Quintanaa698f422009-04-08 19:14:54 -07004489 private void close() {
4490 synchronized (mSessions) {
4491 if (mSessions.remove(toString()) == null) {
4492 // the session was already closed, so bail out now
4493 return;
4494 }
4495 }
4496 if (mResponse != null) {
4497 // stop listening for response deaths
4498 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4499
4500 // clear this so that we don't accidentally send any further results
4501 mResponse = null;
4502 }
4503 cancelTimeout();
4504 unbind();
4505 }
4506
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004507 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004508 public void binderDied() {
4509 mResponse = null;
4510 close();
4511 }
4512
4513 protected String toDebugString() {
4514 return toDebugString(SystemClock.elapsedRealtime());
4515 }
4516
4517 protected String toDebugString(long now) {
4518 return "Session: expectLaunch " + mExpectActivityLaunch
4519 + ", connected " + (mAuthenticator != null)
4520 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4521 + "/" + mNumErrors + ")"
4522 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4523 }
4524
Fred Quintana60307342009-03-24 22:48:12 -07004525 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004526 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4527 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4528 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004529 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004530 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004531 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004532 }
4533 }
4534
4535 private void unbind() {
4536 if (mAuthenticator != null) {
4537 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004538 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004539 }
4540 }
4541
Fred Quintana60307342009-03-24 22:48:12 -07004542 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004543 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004544 }
4545
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004546 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004547 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004548 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004549 try {
4550 run();
4551 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004552 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004553 "remote exception");
4554 }
Fred Quintana60307342009-03-24 22:48:12 -07004555 }
4556
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004557 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004558 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004559 mAuthenticator = null;
4560 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004561 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004562 try {
4563 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4564 "disconnected");
4565 } catch (RemoteException e) {
4566 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4567 Log.v(TAG, "Session.onServiceDisconnected: "
4568 + "caught RemoteException while responding", e);
4569 }
4570 }
Fred Quintana60307342009-03-24 22:48:12 -07004571 }
4572 }
4573
Fred Quintanab839afc2009-10-14 15:57:28 -07004574 public abstract void run() throws RemoteException;
4575
Fred Quintana60307342009-03-24 22:48:12 -07004576 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004577 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004578 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004579 try {
4580 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4581 "timeout");
4582 } catch (RemoteException e) {
4583 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4584 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4585 e);
4586 }
4587 }
Fred Quintana60307342009-03-24 22:48:12 -07004588 }
4589 }
4590
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004591 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004592 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004593 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004594 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004595 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004596 if (result != null) {
4597 boolean isSuccessfulConfirmCreds = result.getBoolean(
4598 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004599 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004600 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4601 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004602 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004603 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4604 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004605 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004606 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004607 if (needUpdate || mAuthDetailsRequired) {
4608 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4609 if (needUpdate && accountPresent) {
4610 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4611 }
4612 if (mAuthDetailsRequired) {
4613 long lastAuthenticatedTime = -1;
4614 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004615 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004616 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004617 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004618 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004619 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004620 lastAuthenticatedTime);
4621 }
4622 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004623 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004624 if (result != null
4625 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004626 checkKeyIntent(
4627 Binder.getCallingUid(),
4628 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004629 }
4630 if (result != null
4631 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004632 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4633 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004634 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4635 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004636 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4637 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004638 }
Fred Quintana60307342009-03-24 22:48:12 -07004639 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004640 IAccountManagerResponse response;
4641 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004642 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004643 response = mResponse;
4644 } else {
4645 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004646 }
Fred Quintana60307342009-03-24 22:48:12 -07004647 if (response != null) {
4648 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004649 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004650 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4651 Log.v(TAG, getClass().getSimpleName()
4652 + " calling onError() on response " + response);
4653 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004654 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004655 "null bundle returned");
4656 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004657 if (mStripAuthTokenFromResult) {
4658 result.remove(AccountManager.KEY_AUTHTOKEN);
4659 }
Fred Quintana56285a62010-12-02 14:20:51 -08004660 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4661 Log.v(TAG, getClass().getSimpleName()
4662 + " calling onResult() on response " + response);
4663 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004664 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4665 (intent == null)) {
4666 // All AccountManager error codes are greater than 0
4667 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4668 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4669 } else {
4670 response.onResult(result);
4671 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004672 }
Fred Quintana60307342009-03-24 22:48:12 -07004673 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004674 // if the caller is dead then there is no one to care about remote exceptions
4675 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4676 Log.v(TAG, "failure while notifying response", e);
4677 }
Fred Quintana60307342009-03-24 22:48:12 -07004678 }
4679 }
4680 }
Fred Quintana60307342009-03-24 22:48:12 -07004681
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004682 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004683 public void onRequestContinued() {
4684 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004685 }
4686
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004687 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004688 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004689 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004690 IAccountManagerResponse response = getResponseAndClose();
4691 if (response != null) {
4692 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004693 Log.v(TAG, getClass().getSimpleName()
4694 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004695 }
4696 try {
4697 response.onError(errorCode, errorMessage);
4698 } catch (RemoteException e) {
4699 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4700 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4701 }
4702 }
4703 } else {
4704 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4705 Log.v(TAG, "Session.onError: already closed");
4706 }
Fred Quintana60307342009-03-24 22:48:12 -07004707 }
4708 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004709
4710 /**
4711 * find the component name for the authenticator and initiate a bind
4712 * if no authenticator or the bind fails then return false, otherwise return true
4713 */
4714 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004715 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4716 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4717 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004718 if (authenticatorInfo == null) {
4719 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4720 Log.v(TAG, "there is no authenticator for " + authenticatorType
4721 + ", bailing out");
4722 }
4723 return false;
4724 }
4725
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004726 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004727 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004728 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4729 + " which isn't encryption aware");
4730 return false;
4731 }
4732
Fred Quintanab839afc2009-10-14 15:57:28 -07004733 Intent intent = new Intent();
4734 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4735 intent.setComponent(authenticatorInfo.componentName);
4736 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4737 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4738 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004739 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004740 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004741 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4742 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4743 }
4744 return false;
4745 }
4746
Fred Quintanab839afc2009-10-14 15:57:28 -07004747 return true;
4748 }
Fred Quintana60307342009-03-24 22:48:12 -07004749 }
4750
Svet Ganov5d09c992016-09-07 09:57:41 -07004751 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004752 MessageHandler(Looper looper) {
4753 super(looper);
4754 }
Costin Manolache3348f142009-09-29 18:58:36 -07004755
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004756 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004757 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004758 switch (msg.what) {
4759 case MESSAGE_TIMED_OUT:
4760 Session session = (Session)msg.obj;
4761 session.onTimedOut();
4762 break;
4763
Amith Yamasani5be347b2013-03-31 17:44:31 -07004764 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004765 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004766 break;
4767
Fred Quintana60307342009-03-24 22:48:12 -07004768 default:
4769 throw new IllegalStateException("unhandled message: " + msg.what);
4770 }
4771 }
4772 }
4773
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004774 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004775 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004776 }
4777
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004778 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004779 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004780 }
4781
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004782 /*
4783 * This function receives an opened writable database.
4784 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004785 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004786 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004787 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004788 }
4789
4790 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004791 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004792 */
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, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004795
4796 class LogRecordTask implements Runnable {
4797 private final String action;
4798 private final String tableName;
4799 private final long accountId;
4800 private final UserAccounts userAccount;
4801 private final int callingUid;
4802 private final long userDebugDbInsertionPoint;
4803
4804 LogRecordTask(final String action,
4805 final String tableName,
4806 final long accountId,
4807 final UserAccounts userAccount,
4808 final int callingUid,
4809 final long userDebugDbInsertionPoint) {
4810 this.action = action;
4811 this.tableName = tableName;
4812 this.accountId = accountId;
4813 this.userAccount = userAccount;
4814 this.callingUid = callingUid;
4815 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4816 }
4817
4818 public void run() {
4819 SQLiteStatement logStatement = userAccount.statementForLogging;
4820 logStatement.bindLong(1, accountId);
4821 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004822 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004823 logStatement.bindLong(4, callingUid);
4824 logStatement.bindString(5, tableName);
4825 logStatement.bindLong(6, userDebugDbInsertionPoint);
4826 logStatement.execute();
4827 logStatement.clearBindings();
4828 }
4829 }
4830
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004831 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4832 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004833 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004834 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004835 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004836 }
4837
4838 /*
4839 * This should only be called once to compile the sql statement for logging
4840 * and to find the insertion point.
4841 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004842 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4843 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4844 .calculateDebugTableInsertionPoint();
4845 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004846 }
4847
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004848 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004849 return asBinder();
4850 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004851
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004852 /**
4853 * Searches array of arguments for the specified string
4854 * @param args array of argument strings
4855 * @param value value to search for
4856 * @return true if the value is contained in the array
4857 */
4858 private static boolean scanArgs(String[] args, String value) {
4859 if (args != null) {
4860 for (String arg : args) {
4861 if (value.equals(arg)) {
4862 return true;
4863 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004864 }
4865 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004866 return false;
4867 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004868
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004869 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004870 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004871 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004872 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004873 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004874
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004875 final List<UserInfo> users = getUserManager().getUsers();
4876 for (UserInfo user : users) {
4877 ipw.println("User " + user + ":");
4878 ipw.increaseIndent();
4879 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4880 ipw.println();
4881 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004882 }
4883 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004884
Amith Yamasani04e0d262012-02-14 11:50:53 -08004885 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4886 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004887 if (isCheckinRequest) {
4888 // This is a checkin request. *Only* upload the account types and the count of
4889 // each.
4890 synchronized (userAccounts.dbLock) {
4891 userAccounts.accountsDb.dumpDeAccountsTable(fout);
4892 }
4893 } else {
4894 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
4895 Process.SYSTEM_UID, null /* packageName */, false);
4896 fout.println("Accounts: " + accounts.length);
4897 for (Account account : accounts) {
4898 fout.println(" " + account);
4899 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004900
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004901 // Add debug information.
4902 fout.println();
4903 synchronized (userAccounts.dbLock) {
4904 userAccounts.accountsDb.dumpDebugTable(fout);
4905 }
4906 fout.println();
4907 synchronized (mSessions) {
4908 final long now = SystemClock.elapsedRealtime();
4909 fout.println("Active Sessions: " + mSessions.size());
4910 for (Session session : mSessions.values()) {
4911 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07004912 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004913 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004914
4915 fout.println();
4916 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004917 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004918 }
4919
Amith Yamasani04e0d262012-02-14 11:50:53 -08004920 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004921 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004922 long identityToken = clearCallingIdentity();
4923 try {
4924 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4925 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4926 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004927
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004928 if (intent.getComponent() != null &&
4929 GrantCredentialsPermissionActivity.class.getName().equals(
4930 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004931 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004932 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004933 Context contextForUser = getContextForUser(new UserHandle(userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004934 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07004935 intent.addCategory(String.valueOf(notificationId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004936
Fred Quintana33f889a2009-09-14 17:31:26 -07004937 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004938 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004939 Notification n =
4940 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004941 .setWhen(0)
4942 .setSmallIcon(android.R.drawable.stat_sys_warning)
4943 .setColor(contextForUser.getColor(
4944 com.android.internal.R.color.system_notification_accent_color))
4945 .setContentTitle(String.format(notificationTitleFormat, account.name))
4946 .setContentText(message)
4947 .setContentIntent(PendingIntent.getActivityAsUser(
4948 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004949 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004950 .build();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004951 installNotification(notificationId, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004952 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004953 } finally {
4954 restoreCallingIdentity(identityToken);
4955 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004956 }
4957
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004958 private void installNotification(int notificationId, final Notification notification,
4959 String packageName, int userId) {
4960 final long token = clearCallingIdentity();
4961 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004962 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004963 try {
4964 notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
4965 notificationId, notification, new int[1], userId);
4966 } catch (RemoteException e) {
4967 /* ignore - local call */
4968 }
4969 } finally {
4970 Binder.restoreCallingIdentity(token);
4971 }
Fred Quintana56285a62010-12-02 14:20:51 -08004972 }
4973
Fyodor Kupolovda993802016-09-21 14:47:10 -07004974 private void cancelNotification(int id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004975 cancelNotification(id, mContext.getPackageName(), user);
4976 }
4977
Fyodor Kupolovda993802016-09-21 14:47:10 -07004978 private void cancelNotification(int id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004979 long identityToken = clearCallingIdentity();
4980 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004981 INotificationManager service = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004982 service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
4983 } catch (RemoteException e) {
4984 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004985 } finally {
4986 restoreCallingIdentity(identityToken);
4987 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004988 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004989
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004990 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
4991 final long identity = Binder.clearCallingIdentity();
4992 try {
4993 IPackageManager pm = ActivityThread.getPackageManager();
4994 for (String perm : permissions) {
4995 if (pm.checkPermission(perm, packageName, userId)
4996 == PackageManager.PERMISSION_GRANTED) {
4997 return true;
4998 }
4999 }
5000 } catch (RemoteException e) {
5001 /* ignore - local call */
5002 } finally {
5003 Binder.restoreCallingIdentity(identity);
5004 }
5005 return false;
5006 }
5007
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005008 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5009 for (String perm : permissions) {
5010 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5011 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5012 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5013 }
5014 final int opCode = AppOpsManager.permissionToOpCode(perm);
5015 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5016 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5017 return true;
5018 }
5019 }
5020 }
5021 return false;
5022 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005023
Amith Yamasani67df64b2012-12-14 12:09:36 -08005024 private int handleIncomingUser(int userId) {
5025 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005026 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005027 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5028 } catch (RemoteException re) {
5029 // Shouldn't happen, local.
5030 }
5031 return userId;
5032 }
5033
Christopher Tateccbf84f2013-05-08 15:25:41 -07005034 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005035 String[] packages;
5036 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005037 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005038 packages = mPackageManager.getPackagesForUid(callingUid);
5039 } finally {
5040 Binder.restoreCallingIdentity(identityToken);
5041 }
5042 if (packages == null) {
5043 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005044 return false;
5045 }
Fred Quintana7be59642009-08-24 18:29:25 -07005046 for (String name : packages) {
5047 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005048 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08005049 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08005050 && (packageInfo.applicationInfo.privateFlags
5051 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07005052 return true;
5053 }
5054 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005055 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07005056 return false;
5057 }
5058 }
5059 return false;
5060 }
5061
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005062 private boolean permissionIsGranted(
5063 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005064 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5065 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5066 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5067 }
5068 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005069 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005070
5071 if (isPrivileged(callerUid)) {
5072 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5073 Log.v(TAG, "Access to " + account + " granted calling uid "
5074 + callerUid + " privileged");
5075 }
5076 return true;
5077 }
5078 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5079 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5080 Log.v(TAG, "Access to " + account + " granted calling uid "
5081 + callerUid + " manages the account");
5082 }
5083 return true;
5084 }
5085 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5086 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5087 Log.v(TAG, "Access to " + account + " granted calling uid "
5088 + callerUid + " user granted access");
5089 }
5090 return true;
5091 }
5092
5093 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5094 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5095 }
5096
5097 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005098 }
5099
Svetoslavf3f02ac2015-09-08 14:36:35 -07005100 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5101 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005102 if (accountType == null) {
5103 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005104 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005105 return getTypesVisibleToCaller(callingUid, userId,
5106 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005107 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005108 }
5109
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005110 // Method checks visibility for applications targeing API level below {@link
5111 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005112 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005113 private boolean checkGetAccountsPermission(String packageName, int userId) {
5114 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5115 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5116 }
5117
5118 private boolean checkReadContactsPermission(String packageName, int userId) {
5119 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5120 }
5121
5122 /**
5123 * Method checks package uid and signature with Authenticator which manages accountType.
5124 *
5125 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5126 * SIGNATURE_CHECK_MISMATCH otherwise.
5127 */
5128 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5129 if (accountType == null) {
5130 return SIGNATURE_CHECK_MISMATCH;
5131 }
5132
5133 long identityToken = Binder.clearCallingIdentity();
5134 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5135 try {
5136 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5137 } finally {
5138 Binder.restoreCallingIdentity(identityToken);
5139 }
5140 // Check for signature match with Authenticator.
5141 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5142 : serviceInfos) {
5143 if (accountType.equals(serviceInfo.type.type)) {
5144 if (serviceInfo.uid == callingUid) {
5145 return SIGNATURE_CHECK_UID_MATCH;
5146 }
5147 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5148 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5149 return SIGNATURE_CHECK_MATCH;
5150 }
5151 }
5152 }
5153 return SIGNATURE_CHECK_MISMATCH;
5154 }
5155
5156 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005157 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5158 if (accountType == null) {
5159 return false;
5160 } else {
5161 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5162 }
5163 }
5164
Svetoslavf3f02ac2015-09-08 14:36:35 -07005165 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5166 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005167 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005168 }
5169
5170 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005171 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005172 }
5173
5174 private List<String> getTypesForCaller(
5175 int callingUid, int userId, boolean isOtherwisePermitted) {
5176 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005177 long identityToken = Binder.clearCallingIdentity();
5178 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5179 try {
5180 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5181 } finally {
5182 Binder.restoreCallingIdentity(identityToken);
5183 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005184 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005185 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005186 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5187 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005188 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005189 }
5190 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005191 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005192 }
5193
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005194 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5195 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5196 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5197 if (account.name.equals(accountName)) {
5198 return true;
5199 }
5200 }
5201 }
5202 return false;
5203 }
5204
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005205 private static void checkManageUsersPermission(String message) {
5206 if (ActivityManager.checkComponentPermission(
5207 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5208 != PackageManager.PERMISSION_GRANTED) {
5209 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5210 }
5211 }
5212
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005213 private static void checkManageOrCreateUsersPermission(String message) {
5214 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5215 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5216 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5217 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5218 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5219 + message);
5220 }
5221 }
5222
Amith Yamasani04e0d262012-02-14 11:50:53 -08005223 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5224 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005225 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005226 return true;
5227 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005228 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005229 synchronized (accounts.dbLock) {
5230 synchronized (accounts.cacheLock) {
5231 long grantsCount;
5232 if (authTokenType != null) {
5233 grantsCount = accounts.accountsDb
5234 .findMatchingGrantsCount(callerUid, authTokenType, account);
5235 } else {
5236 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5237 account);
5238 }
5239 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005240
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005241 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5242 // TODO: Skip this check when running automated tests. Replace this
5243 // with a more general solution.
5244 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5245 + authTokenType + " by uid " + callerUid
5246 + " but ignoring since device is in test harness.");
5247 return true;
5248 }
5249 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005250 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005251 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005252 }
5253
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005254 private boolean isSystemUid(int callingUid) {
5255 String[] packages = null;
5256 long ident = Binder.clearCallingIdentity();
5257 try {
5258 packages = mPackageManager.getPackagesForUid(callingUid);
5259 } finally {
5260 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005261 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005262 if (packages != null) {
5263 for (String name : packages) {
5264 try {
5265 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5266 if (packageInfo != null
5267 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5268 != 0) {
5269 return true;
5270 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005271 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005272 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5273 }
5274 }
5275 } else {
5276 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005277 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005278 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005279 }
5280
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005281 /** Succeeds if any of the specified permissions are granted. */
5282 private void checkReadAccountsPermitted(
5283 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005284 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005285 int userId,
5286 String opPackageName) {
5287 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005288 String msg = String.format(
5289 "caller uid %s cannot access %s accounts",
5290 callingUid,
5291 accountType);
5292 Log.w(TAG, " " + msg);
5293 throw new SecurityException(msg);
5294 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005295 }
5296
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005297 private boolean canUserModifyAccounts(int userId, int callingUid) {
5298 // the managing app can always modify accounts
5299 if (isProfileOwner(callingUid)) {
5300 return true;
5301 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005302 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5303 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5304 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005305 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005306 return true;
5307 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005308
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005309 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5310 // the managing app can always modify accounts
5311 if (isProfileOwner(callingUid)) {
5312 return true;
5313 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005314 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5315 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005316 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005317 if (typesArray == null) {
5318 return true;
5319 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005320 for (String forbiddenType : typesArray) {
5321 if (forbiddenType.equals(accountType)) {
5322 return false;
5323 }
5324 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005325 return true;
5326 }
5327
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005328 private boolean isProfileOwner(int uid) {
5329 final DevicePolicyManagerInternal dpmi =
5330 LocalServices.getService(DevicePolicyManagerInternal.class);
5331 return (dpmi != null)
5332 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5333 }
5334
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005335 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005336 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5337 throws RemoteException {
5338 final int callingUid = getCallingUid();
5339
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005340 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005341 throw new SecurityException();
5342 }
5343
5344 if (value) {
5345 grantAppPermission(account, authTokenType, uid);
5346 } else {
5347 revokeAppPermission(account, authTokenType, uid);
5348 }
5349 }
5350
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005351 /**
5352 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5353 * <p>
5354 * Although this is public it can only be accessed via the AccountManagerService object
5355 * which is in the system. This means we don't need to protect it with permissions.
5356 * @hide
5357 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005358 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005359 if (account == null || authTokenType == null) {
5360 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005361 return;
5362 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005363 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005364 synchronized (accounts.dbLock) {
5365 synchronized (accounts.cacheLock) {
5366 long accountId = accounts.accountsDb.findDeAccountId(account);
5367 if (accountId >= 0) {
5368 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5369 }
5370 cancelNotification(
5371 getCredentialPermissionNotificationId(account, authTokenType, uid),
5372 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005373
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005374 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5375 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005376 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005377
5378 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5379 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5380 : mAppPermissionChangeListeners) {
5381 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5382 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005383 }
5384
5385 /**
5386 * Don't allow callers with the given uid permission to get credentials for
5387 * account/authTokenType.
5388 * <p>
5389 * Although this is public it can only be accessed via the AccountManagerService object
5390 * which is in the system. This means we don't need to protect it with permissions.
5391 * @hide
5392 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005393 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005394 if (account == null || authTokenType == null) {
5395 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005396 return;
5397 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005398 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005399 synchronized (accounts.dbLock) {
5400 synchronized (accounts.cacheLock) {
5401 accounts.accountsDb.beginTransaction();
5402 try {
5403 long accountId = accounts.accountsDb.findDeAccountId(account);
5404 if (accountId >= 0) {
5405 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5406 accountId, authTokenType, uid);
5407 accounts.accountsDb.setTransactionSuccessful();
5408 }
5409 } finally {
5410 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005411 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005412
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005413 cancelNotification(
5414 getCredentialPermissionNotificationId(account, authTokenType, uid),
5415 UserHandle.of(accounts.userId));
5416 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005417 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005418
5419 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5420 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5421 : mAppPermissionChangeListeners) {
5422 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5423 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005424 }
Fred Quintana56285a62010-12-02 14:20:51 -08005425
Amith Yamasani04e0d262012-02-14 11:50:53 -08005426 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5427 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005428 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005429 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005430 for (Account curAccount : oldAccountsForType) {
5431 if (!curAccount.equals(account)) {
5432 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005433 }
5434 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005435 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005436 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005437 } else {
5438 Account[] newAccountsForType = new Account[newAccountsList.size()];
5439 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005440 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005441 }
Fred Quintana56285a62010-12-02 14:20:51 -08005442 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005443 accounts.userDataCache.remove(account);
5444 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005445 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005446 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005447 }
5448
5449 /**
5450 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005451 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5452 * processes and if you will return this account to apps you should return the result.
5453 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005454 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005455 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005456 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005457 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5458 Account[] newAccountsForType = new Account[oldLength + 1];
5459 if (accountsForType != null) {
5460 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005461 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005462 String token = account.getAccessId() != null ? account.getAccessId()
5463 : UUID.randomUUID().toString();
5464 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005465 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005466 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005467 }
5468
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005469 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005470 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005471 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005472 String visibilityFilterPackage = callingPackage;
5473 if (visibilityFilterPackage == null) {
5474 visibilityFilterPackage = getPackageNameForUid(callingUid);
5475 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005476 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005477 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005478 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005479 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5480 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5481 || (includeManagedNotVisible
5482 && (visibility
5483 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5484 firstPass.put(account, visibility);
5485 }
5486 }
5487 Map<Account, Integer> secondPass =
5488 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5489
5490 Account[] filtered = new Account[secondPass.size()];
5491 filtered = secondPass.keySet().toArray(filtered);
5492 return filtered;
5493 }
5494
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005495 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005496 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005497 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005498 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005499 // first part is to filter shared accounts.
5500 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005501 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005502 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005503 return unfiltered;
5504 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005505 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005506 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005507 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005508 if (packages == null) {
5509 packages = new String[] {};
5510 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005511 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005512 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005513 // This might be a temporary way to specify a visible list
5514 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005515 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5516 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005517 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005518 return unfiltered;
5519 }
5520 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005521 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005522 if (ArrayUtils.isEmpty(sharedAccounts)) {
5523 return unfiltered;
5524 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005525 String requiredAccountType = "";
5526 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005527 // If there's an explicit callingPackage specified, check if that package
5528 // opted in to see restricted accounts.
5529 if (callingPackage != null) {
5530 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005531 if (pi != null && pi.restrictedAccountType != null) {
5532 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005533 }
5534 } else {
5535 // Otherwise check if the callingUid has a package that has opted in
5536 for (String packageName : packages) {
5537 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5538 if (pi != null && pi.restrictedAccountType != null) {
5539 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005540 break;
5541 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005542 }
5543 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005544 } catch (NameNotFoundException e) {
5545 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005546 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005547 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005548 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5549 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005550 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005551 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005552 } else {
5553 boolean found = false;
5554 for (Account shared : sharedAccounts) {
5555 if (shared.equals(account)) {
5556 found = true;
5557 break;
5558 }
5559 }
5560 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005561 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005562 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005563 }
5564 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005565 return filtered;
5566 } else {
5567 return unfiltered;
5568 }
5569 }
5570
Amith Yamasani27db4682013-03-30 17:07:47 -07005571 /*
5572 * packageName can be null. If not null, it should be used to filter out restricted accounts
5573 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005574 *
5575 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5576 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005577 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005578 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005579 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005580 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005581 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5582 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005583 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005584 Account[] accounts;
5585 synchronized (userAccounts.cacheLock) {
5586 accounts = userAccounts.accountCache.get(accountType);
5587 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005588 if (accounts == null) {
5589 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005590 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005591 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5592 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005593 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005594 } else {
5595 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005596 Account[] accountsArray;
5597 synchronized (userAccounts.cacheLock) {
5598 for (Account[] accounts : userAccounts.accountCache.values()) {
5599 totalLength += accounts.length;
5600 }
5601 if (totalLength == 0) {
5602 return EMPTY_ACCOUNT_ARRAY;
5603 }
5604 accountsArray = new Account[totalLength];
5605 totalLength = 0;
5606 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5607 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5608 accountsOfType.length);
5609 totalLength += accountsOfType.length;
5610 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005611 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005612 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005613 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005614 }
5615 }
5616
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005617 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005618 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005619 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005620 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005621 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005622 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005623 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005624 }
5625 if (value == null) {
5626 userDataForAccount.remove(key);
5627 } else {
5628 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005629 }
5630 }
5631
Carlos Valdivia91979be2015-05-22 14:11:35 -07005632 protected String readCachedTokenInternal(
5633 UserAccounts accounts,
5634 Account account,
5635 String tokenType,
5636 String callingPackage,
5637 byte[] pkgSigDigest) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005638 synchronized (accounts.dbLock) {
5639 synchronized (accounts.cacheLock) {
5640 return accounts.accountTokenCaches.get(
5641 account, tokenType, callingPackage, pkgSigDigest);
5642 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07005643 }
5644 }
5645
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005646 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005647 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005648 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005649 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005650 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005651 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005652 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005653 }
5654 if (value == null) {
5655 authTokensForAccount.remove(key);
5656 } else {
5657 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005658 }
5659 }
5660
Amith Yamasani04e0d262012-02-14 11:50:53 -08005661 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5662 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005663 // Fast path - check if account is already cached
5664 synchronized (accounts.cacheLock) {
5665 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5666 if (authTokensForAccount != null) {
5667 return authTokensForAccount.get(authTokenType);
5668 }
5669 }
5670 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005671 synchronized (accounts.dbLock) {
5672 synchronized (accounts.cacheLock) {
5673 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5674 if (authTokensForAccount == null) {
5675 // need to populate the cache for this account
5676 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
5677 accounts.authTokenCache.put(account, authTokensForAccount);
5678 }
5679 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08005680 }
Fred Quintana56285a62010-12-02 14:20:51 -08005681 }
5682 }
5683
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005684 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
5685 Map<String, String> userDataForAccount;
5686 // Fast path - check if data is already cached
5687 synchronized (accounts.cacheLock) {
5688 userDataForAccount = accounts.userDataCache.get(account);
5689 }
5690 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00005691 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005692 synchronized (accounts.dbLock) {
5693 synchronized (accounts.cacheLock) {
5694 userDataForAccount = accounts.userDataCache.get(account);
5695 if (userDataForAccount == null) {
5696 // need to populate the cache for this account
5697 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
5698 accounts.userDataCache.put(account, userDataForAccount);
5699 }
5700 }
5701 }
Fred Quintana56285a62010-12-02 14:20:51 -08005702 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005703 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005704 }
5705
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005706 private Context getContextForUser(UserHandle user) {
5707 try {
5708 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5709 } catch (NameNotFoundException e) {
5710 // Default to mContext, not finding the package system is running as is unlikely.
5711 return mContext;
5712 }
5713 }
Sandra Kwan78812282015-11-04 11:19:47 -08005714
5715 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5716 try {
5717 response.onResult(result);
5718 } catch (RemoteException e) {
5719 // if the caller is dead then there is no one to care about remote
5720 // exceptions
5721 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5722 Log.v(TAG, "failure while notifying response", e);
5723 }
5724 }
5725 }
5726
5727 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5728 String errorMessage) {
5729 try {
5730 response.onError(errorCode, errorMessage);
5731 } catch (RemoteException e) {
5732 // if the caller is dead then there is no one to care about remote
5733 // exceptions
5734 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5735 Log.v(TAG, "failure while notifying response", e);
5736 }
5737 }
5738 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005739
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005740 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005741 private final Object mLock = new Object();
5742
5743 @GuardedBy("mLock")
5744 private AccountManagerBackupHelper mBackupHelper;
5745
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005746 @Override
5747 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5748 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5749 if (account == null) {
5750 Slog.w(TAG, "account cannot be null");
5751 return;
5752 }
5753 if (packageName == null) {
5754 Slog.w(TAG, "packageName cannot be null");
5755 return;
5756 }
5757 if (userId < UserHandle.USER_SYSTEM) {
5758 Slog.w(TAG, "user id must be concrete");
5759 return;
5760 }
5761 if (callback == null) {
5762 Slog.w(TAG, "callback cannot be null");
5763 return;
5764 }
5765
Svet Ganovf6d424f12016-09-20 20:18:53 -07005766 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5767 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005768 Bundle result = new Bundle();
5769 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5770 callback.sendResult(result);
5771 return;
5772 }
5773
5774 final int uid;
5775 try {
5776 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5777 } catch (NameNotFoundException e) {
5778 Slog.e(TAG, "Unknown package " + packageName);
5779 return;
5780 }
5781
5782 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005783 final UserAccounts userAccounts;
5784 synchronized (mUsers) {
5785 userAccounts = mUsers.get(userId);
5786 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04005787 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005788 doNotification(userAccounts, account, null, intent, packageName, userId);
5789 }
5790
5791 @Override
5792 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5793 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5794 mAppPermissionChangeListeners.add(listener);
5795 }
5796
5797 @Override
5798 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5799 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005800 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005801
5802 @Override
5803 public byte[] backupAccountAccessPermissions(int userId) {
5804 synchronized (mLock) {
5805 if (mBackupHelper == null) {
5806 mBackupHelper = new AccountManagerBackupHelper(
5807 AccountManagerService.this, this);
5808 }
5809 return mBackupHelper.backupAccountAccessPermissions(userId);
5810 }
5811 }
5812
5813 @Override
5814 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5815 synchronized (mLock) {
5816 if (mBackupHelper == null) {
5817 mBackupHelper = new AccountManagerBackupHelper(
5818 AccountManagerService.this, this);
5819 }
5820 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5821 }
5822 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005823 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005824
5825 @VisibleForTesting
5826 static class Injector {
5827 private final Context mContext;
5828
5829 public Injector(Context context) {
5830 mContext = context;
5831 }
5832
5833 Looper getMessageHandlerLooper() {
5834 ServiceThread serviceThread = new ServiceThread(TAG,
5835 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5836 serviceThread.start();
5837 return serviceThread.getLooper();
5838 }
5839
5840 Context getContext() {
5841 return mContext;
5842 }
5843
5844 void addLocalService(AccountManagerInternal service) {
5845 LocalServices.addService(AccountManagerInternal.class, service);
5846 }
5847
5848 String getDeDatabaseName(int userId) {
5849 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5850 AccountsDb.DE_DATABASE_NAME);
5851 return databaseFile.getPath();
5852 }
5853
5854 String getCeDatabaseName(int userId) {
5855 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5856 AccountsDb.CE_DATABASE_NAME);
5857 return databaseFile.getPath();
5858 }
5859
5860 String getPreNDatabaseName(int userId) {
5861 File systemDir = Environment.getDataSystemDirectory();
5862 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5863 PRE_N_DATABASE_NAME);
5864 if (userId == 0) {
5865 // Migrate old file, if it exists, to the new location.
5866 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005867 // accidentally created in the old location,
5868 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005869 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5870 if (oldFile.exists() && !databaseFile.exists()) {
5871 // Check for use directory; create if it doesn't exist, else renameTo will fail
5872 File userDir = Environment.getUserSystemDirectory(userId);
5873 if (!userDir.exists()) {
5874 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005875 throw new IllegalStateException(
5876 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005877 }
5878 }
5879 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005880 throw new IllegalStateException(
5881 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005882 }
5883 }
5884 }
5885 return databaseFile.getPath();
5886 }
5887
5888 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5889 return new AccountAuthenticatorCache(mContext);
5890 }
5891
5892 INotificationManager getNotificationManager() {
5893 return NotificationManager.getService();
5894 }
5895 }
Fred Quintana60307342009-03-24 22:48:12 -07005896}