blob: 0ffc77923f1a473ef3dbd5406d2226aa5052f887 [file] [log] [blame]
Fred Quintana60307342009-03-24 22:48:12 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.accounts;
Fred Quintana60307342009-03-24 22:48:12 -070018
Doug Zongker885cfc232009-10-21 16:52:44 -070019import android.Manifest;
Carlos Valdivia91979be2015-05-22 14:11:35 -070020import android.accounts.AbstractAccountAuthenticator;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080021import android.accounts.Account;
22import android.accounts.AccountAndUser;
23import android.accounts.AccountAuthenticatorResponse;
24import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070025import android.accounts.AccountManagerInternal;
sunjianf29d5492017-05-11 15:42:31 -070026import android.accounts.AccountManagerResponse;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080027import android.accounts.AuthenticatorDescription;
Amith Yamasani23c8b962013-04-10 13:37:18 -070028import android.accounts.CantAddAccountActivity;
sunjianf29d5492017-05-11 15:42:31 -070029import android.accounts.ChooseAccountActivity;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080030import android.accounts.GrantCredentialsPermissionActivity;
31import android.accounts.IAccountAuthenticator;
32import android.accounts.IAccountAuthenticatorResponse;
33import android.accounts.IAccountManager;
34import android.accounts.IAccountManagerResponse;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070035import android.annotation.IntRange;
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070036import android.annotation.NonNull;
Svet Ganovf6d424f12016-09-20 20:18:53 -070037import android.annotation.Nullable;
Brett Chabot3b4fcbc2011-01-09 13:41:02 -080038import android.app.ActivityManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070039import android.app.ActivityThread;
Svetoslavf3f02ac2015-09-08 14:36:35 -070040import android.app.AppOpsManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070041import android.app.INotificationManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070042import android.app.Notification;
43import android.app.NotificationManager;
44import android.app.PendingIntent;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000045import android.app.admin.DeviceAdminInfo;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010046import android.app.admin.DevicePolicyManager;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000047import android.app.admin.DevicePolicyManagerInternal;
Fred Quintanaa698f422009-04-08 19:14:54 -070048import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070049import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070050import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070053import android.content.IntentSender;
Fred Quintanab839afc2009-10-14 15:57:28 -070054import android.content.ServiceConnection;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -080055import android.content.pm.ActivityInfo;
Doug Zongker885cfc232009-10-21 16:52:44 -070056import android.content.pm.ApplicationInfo;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070057import android.content.pm.IPackageManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070058import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070059import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070060import android.content.pm.PackageManager.NameNotFoundException;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070061import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070062import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070063import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070064import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070065import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070066import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070067import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070068import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070069import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080070import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070071import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070072import android.os.IBinder;
73import android.os.Looper;
74import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070075import android.os.Parcel;
sunjianf29d5492017-05-11 15:42:31 -070076import android.os.Parcelable;
Amith Yamasani27db4682013-03-30 17:07:47 -070077import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070078import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070079import android.os.RemoteException;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080080import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070081import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070082import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070083import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070084import android.text.TextUtils;
85import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070086import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070087import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080088import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070089import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070090
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070091import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070092import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070093import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070094import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040095import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050096import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080097import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060098import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080099import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -0700100import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +0000101import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700102import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600103import com.android.server.SystemService;
104
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700105import com.google.android.collect.Lists;
106import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700107
Oscar Montemayora8529f62009-11-18 10:14:20 -0800108import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700109import java.io.FileDescriptor;
110import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800111import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700112import java.security.MessageDigest;
113import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700114import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700115import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800116import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700117import java.util.Collection;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700118import java.util.Collections;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700119import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700120import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700121import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800122import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700123import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800124import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800125import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700126import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700127import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700128import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700129import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700130import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700131
Fred Quintana60307342009-03-24 22:48:12 -0700132/**
133 * A system service that provides account, password, and authtoken management for all
134 * accounts on the device. Some of these calls are implemented with the help of the corresponding
135 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
136 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700137 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700138 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700139 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700140public class AccountManagerService
141 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800142 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700143 private static final String TAG = "AccountManagerService";
144
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600145 public static class Lifecycle extends SystemService {
146 private AccountManagerService mService;
147
148 public Lifecycle(Context context) {
149 super(context);
150 }
151
152 @Override
153 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700154 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600155 publishBinderService(Context.ACCOUNT_SERVICE, mService);
156 }
157
158 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600159 public void onUnlockUser(int userHandle) {
160 mService.onUnlockUser(userHandle);
161 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700162
163 @Override
Fyodor Kupolovce25ed22017-05-04 11:44:31 -0700164 public void onStopUser(int userHandle) {
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700165 Slog.i(TAG, "onStopUser " + userHandle);
166 mService.purgeUserData(userHandle);
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700167 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600168 }
169
Svet Ganov5d09c992016-09-07 09:57:41 -0700170 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700171
Fred Quintana56285a62010-12-02 14:20:51 -0800172 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700173 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700174 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700175 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800176
Svet Ganov5d09c992016-09-07 09:57:41 -0700177 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700178
Fred Quintana60307342009-03-24 22:48:12 -0700179 // Messages that can be sent on mHandler
180 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700181 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700182
Fred Quintana56285a62010-12-02 14:20:51 -0800183 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700184 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700185 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800186
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800187 private static final int SIGNATURE_CHECK_MISMATCH = 0;
188 private static final int SIGNATURE_CHECK_MATCH = 1;
189 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
190
Carlos Valdivia91979be2015-05-22 14:11:35 -0700191 static {
192 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800193 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
194 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700195 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700196
197 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700198
Amith Yamasani04e0d262012-02-14 11:50:53 -0800199 static class UserAccounts {
200 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700201 final AccountsDb accountsDb;
Chris Wren717a8812017-03-31 15:34:39 -0400202 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
203 credentialsPermissionNotificationIds = new HashMap<>();
204 private final HashMap<Account, NotificationId> signinRequiredNotificationIds
205 = new HashMap<>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700206 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700207 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800208 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700209 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800210 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700211 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800212 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700213 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700214 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700215 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700216 /** protected by the {@link #cacheLock} */
217 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700218
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700219 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700220 * type -> (packageName -> number of active receivers)
221 * type == null is used to get notifications about all account types
222 */
223 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800224
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700225 /**
226 * protected by the {@link #cacheLock}
227 *
228 * Caches the previous names associated with an account. Previous names
229 * should be cached because we expect that when an Account is renamed,
230 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
231 * want to know if the accounts they care about have been renamed.
232 *
233 * The previous names are wrapped in an {@link AtomicReference} so that
234 * we can distinguish between those accounts with no previous names and
235 * those whose previous names haven't been cached (yet).
236 */
237 private final HashMap<Account, AtomicReference<String>> previousNameCache =
238 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800239
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700240 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700241 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700242
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700243 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800244 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700245 synchronized (dbLock) {
246 synchronized (cacheLock) {
247 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
248 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800249 }
250 }
251 }
252
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700253 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600254 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700255 // Not thread-safe. Only use in synchronized context
256 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700257 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
258 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800259
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700260 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700261 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700262
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700263 /**
264 * This should only be called by system code. One should only call this after the service
265 * has started.
266 * @return a reference to the AccountManagerService instance
267 * @hide
268 */
269 public static AccountManagerService getSingleton() {
270 return sThis.get();
271 }
Fred Quintana60307342009-03-24 22:48:12 -0700272
Fyodor Kupolovda993802016-09-21 14:47:10 -0700273 public AccountManagerService(Injector injector) {
274 mInjector = injector;
275 mContext = injector.getContext();
276 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700277 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700278 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
279 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800280 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700281
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700282 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800283
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800284 IntentFilter intentFilter = new IntentFilter();
285 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
286 intentFilter.addDataScheme("package");
287 mContext.registerReceiver(new BroadcastReceiver() {
288 @Override
289 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700290 // Don't delete accounts when updating a authenticator's
291 // package.
292 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700293 /* Purging data requires file io, don't block the main thread. This is probably
294 * less than ideal because we are introducing a race condition where old grants
295 * could be exercised until they are purged. But that race condition existed
296 * anyway with the broadcast receiver.
297 *
298 * Ideally, we would completely clear the cache, purge data from the database,
299 * and then rebuild the cache. All under the cache lock. But that change is too
300 * large at this point.
301 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800302 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700303 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700304 @Override
305 public void run() {
306 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800307 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800308 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700309 }
310 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700311 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700312 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800313 }
314 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800315
Fyodor Kupolovda993802016-09-21 14:47:10 -0700316 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700317
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700318 IntentFilter userFilter = new IntentFilter();
319 userFilter.addAction(Intent.ACTION_USER_REMOVED);
320 mContext.registerReceiverAsUser(new BroadcastReceiver() {
321 @Override
322 public void onReceive(Context context, Intent intent) {
323 String action = intent.getAction();
324 if (Intent.ACTION_USER_REMOVED.equals(action)) {
325 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
326 if (userId < 1) return;
327 Slog.i(TAG, "User " + userId + " removed");
328 purgeUserData(userId);
329 }
330 }
331 }, UserHandle.ALL, userFilter, null, null);
332
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700333 // Need to cancel account request notifications if the update/install can access the account
334 new PackageMonitor() {
335 @Override
336 public void onPackageAdded(String packageName, int uid) {
337 // Called on a handler, and running as the system
338 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
339 }
340
341 @Override
342 public void onPackageUpdateFinished(String packageName, int uid) {
343 // Called on a handler, and running as the system
344 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
345 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700346 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700347
348 // Cancel account request notification if an app op was preventing the account access
349 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
350 new AppOpsManager.OnOpChangedInternalListener() {
351 @Override
352 public void onOpChanged(int op, String packageName) {
353 try {
354 final int userId = ActivityManager.getCurrentUser();
355 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
356 final int mode = mAppOpsManager.checkOpNoThrow(
357 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
358 if (mode == AppOpsManager.MODE_ALLOWED) {
359 final long identity = Binder.clearCallingIdentity();
360 try {
361 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
362 } finally {
363 Binder.restoreCallingIdentity(identity);
364 }
365 }
366 } catch (NameNotFoundException e) {
367 /* ignore */
368 }
369 }
370 });
371
372 // Cancel account request notification if a permission was preventing the account access
373 mPackageManager.addOnPermissionsChangeListener(
374 (int uid) -> {
375 Account[] accounts = null;
376 String[] packageNames = mPackageManager.getPackagesForUid(uid);
377 if (packageNames != null) {
378 final int userId = UserHandle.getUserId(uid);
379 final long identity = Binder.clearCallingIdentity();
380 try {
381 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800382 // if app asked for permission we need to cancel notification even
383 // for O+ applications.
384 if (mPackageManager.checkPermission(
385 Manifest.permission.GET_ACCOUNTS,
386 packageName) != PackageManager.PERMISSION_GRANTED) {
387 continue;
388 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700389
390 if (accounts == null) {
391 accounts = getAccountsAsUser(null, userId, "android");
392 if (ArrayUtils.isEmpty(accounts)) {
393 return;
394 }
395 }
396
397 for (Account account : accounts) {
398 cancelAccountAccessRequestNotificationIfNeeded(
399 account, uid, packageName, true);
400 }
401 }
402 } finally {
403 Binder.restoreCallingIdentity(identity);
404 }
405 }
406 });
407 }
408
409 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
410 boolean checkAccess) {
411 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
412 for (Account account : accounts) {
413 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
414 }
415 }
416
417 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
418 boolean checkAccess) {
419 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
420 for (Account account : accounts) {
421 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
422 }
423 }
424
425 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
426 boolean checkAccess) {
427 String[] packageNames = mPackageManager.getPackagesForUid(uid);
428 if (packageNames != null) {
429 for (String packageName : packageNames) {
430 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
431 packageName, checkAccess);
432 }
433 }
434 }
435
436 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
437 int uid, String packageName, boolean checkAccess) {
438 if (!checkAccess || hasAccountAccess(account, packageName,
439 UserHandle.getUserHandleForUid(uid))) {
440 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700441 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700442 UserHandle.getUserHandleForUid(uid));
443 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800444 }
445
Dianne Hackborn164371f2013-10-01 19:10:13 -0700446 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800447 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800448 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800449 Bundle.setDefusable(extras, true);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700450 int callingUid = Binder.getCallingUid();
451 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800452 if (Log.isLoggable(TAG, Log.VERBOSE)) {
453 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
454 + ", pid " + Binder.getCallingPid());
455 }
456 Preconditions.checkNotNull(account, "account cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800457 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
458 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
459 callingUid, account.type);
460 throw new SecurityException(msg);
461 }
462 /*
463 * Child users are not allowed to add accounts. Only the accounts that are shared by the
464 * parent profile can be added to child profile.
465 *
466 * TODO: Only allow accounts that were shared to be added by a limited user.
467 */
468 // fails if the account already exists
469 long identityToken = clearCallingIdentity();
470 try {
471 UserAccounts accounts = getUserAccounts(userId);
472 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800473 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800474 } finally {
475 restoreCallingIdentity(identityToken);
476 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700477 }
478
479 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800480 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
481 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800482 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700483 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800484 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700485 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800486
487 if ((accountType != null && !managedTypes.contains(accountType))
488 || (accountType == null && !isSystemUid)) {
489 throw new SecurityException(
490 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
491 + callingUid + " with packageName=" + packageName);
492 }
493 if (accountType != null) {
494 managedTypes = new ArrayList<String>();
495 managedTypes.add(accountType);
496 }
497
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800498 long identityToken = clearCallingIdentity();
499 try {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700500 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800501 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700502 accounts);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800503 } finally {
504 restoreCallingIdentity(identityToken);
505 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800506 }
507
508 /*
509 * accountTypes may not be null
510 */
511 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
512 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700513 if (!packageExistsForUser(packageName, accounts.userId)) {
514 Log.d(TAG, "Package not found " + packageName);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800515 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800516 }
517
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800518 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800519 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700520 synchronized (accounts.dbLock) {
521 synchronized (accounts.cacheLock) {
522 final Account[] accountsOfType = accounts.accountCache.get(accountType);
523 if (accountsOfType != null) {
524 for (Account account : accountsOfType) {
525 result.put(account,
526 resolveAccountVisibility(account, packageName, accounts));
527 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800528 }
529 }
530 }
531 }
532 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800533 }
534
535 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800536 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700537 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700538 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700539 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800540 if (!isAccountManagedByCaller(account.type, callingUid, userId)
541 && !isSystemUid(callingUid)) {
542 String msg =
543 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700544 throw new SecurityException(msg);
545 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700546
547 long identityToken = clearCallingIdentity();
548 try {
549 UserAccounts accounts = getUserAccounts(userId);
550 synchronized (accounts.dbLock) {
551 synchronized (accounts.cacheLock) {
552 return getPackagesAndVisibilityForAccountLocked(account, accounts);
553 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700554 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700555 } finally {
556 restoreCallingIdentity(identityToken);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700557 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700558
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800559 }
560
561 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700562 * Returns Map with all package names and visibility values for given account.
563 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800564 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800565 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800566 * @param accounts UserAccount that currently hosts the account and application
567 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700568 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800569 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700570 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800571 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700572 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
573 if (accountVisibility == null) {
574 Log.d(TAG, "Visibility was not initialized");
575 accountVisibility = new HashMap<>();
576 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800577 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700578 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700579 }
580
581 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700582 public int getAccountVisibility(Account account, String packageName) {
583 Preconditions.checkNotNull(account, "account cannot be null");
584 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800585 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700586 int userId = UserHandle.getCallingUserId();
587 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800588 && !isSystemUid(callingUid)) {
589 String msg = String.format(
590 "uid %s cannot get secrets for accounts of type: %s",
591 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700592 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800593 throw new SecurityException(msg);
594 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700595 long identityToken = clearCallingIdentity();
596 try {
597 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyevcbe1bd12017-04-25 17:02:47 -0700598 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
599 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
600 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
601 return visibility;
602 } else {
603 return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
604 }
605 }
606 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) {
607 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
608 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
609 return visibility;
610 } else {
611 return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
612 }
613 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700614 return resolveAccountVisibility(account, packageName, accounts);
615 } finally {
616 restoreCallingIdentity(identityToken);
617 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800618 }
619
620 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800621 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800622 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800623 * @param account The account to check visibility.
624 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800625 * @param accounts UserAccount that currently hosts the account and application
626 *
627 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
628 *
629 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700630 private int getAccountVisibilityFromCache(Account account, String packageName,
631 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700632 synchronized (accounts.cacheLock) {
633 Map<String, Integer> accountVisibility =
634 getPackagesAndVisibilityForAccountLocked(account, accounts);
635 Integer visibility = accountVisibility.get(packageName);
636 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800637 }
638 }
639
640 /**
641 * Method which handles default values for Account visibility.
642 *
643 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800644 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800645 * @param accounts UserAccount that currently hosts the account and application
646 *
647 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
648 *
649 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800650 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800651 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800652 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800653 int uid = -1;
654 try {
655 long identityToken = clearCallingIdentity();
656 try {
657 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
658 } finally {
659 restoreCallingIdentity(identityToken);
660 }
661 } catch (NameNotFoundException e) {
662 Log.d(TAG, "Package not found " + e.getMessage());
663 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800664 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800665
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800666 // System visibility can not be restricted.
667 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
668 return AccountManager.VISIBILITY_VISIBLE;
669 }
670
671 int signatureCheckResult =
672 checkPackageSignature(account.type, uid, accounts.userId);
673
674 // Authenticator can not restrict visibility to itself.
675 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
676 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
677 }
678
679 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700680 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800681
682 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
683 return visibility;
684 }
685
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700686 boolean isPrivileged = isPermittedForPackage(packageName, uid, accounts.userId,
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800687 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
688
689 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800690 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800691 return AccountManager.VISIBILITY_VISIBLE;
692 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800693
694 boolean preO = isPreOApplication(packageName);
695 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700696 || (preO && checkGetAccountsPermission(packageName, uid, accounts.userId))
697 || (checkReadContactsPermission(packageName, uid, accounts.userId)
698 && accountTypeManagesContacts(account.type, accounts.userId))
699 || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800700 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
701 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700702 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800703 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800704 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
705 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
706 }
707 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700708 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800709 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800710 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
711 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
712 }
713 }
714 return visibility;
715 }
716
717 /**
718 * Checks targetSdk for a package;
719 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800720 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800721 *
722 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
723 * undefined
724 */
725 private boolean isPreOApplication(String packageName) {
726 try {
727 long identityToken = clearCallingIdentity();
728 ApplicationInfo applicationInfo;
729 try {
730 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
731 } finally {
732 restoreCallingIdentity(identityToken);
733 }
734
735 if (applicationInfo != null) {
736 int version = applicationInfo.targetSdkVersion;
737 return version < android.os.Build.VERSION_CODES.O;
738 }
739 return true;
740 } catch (NameNotFoundException e) {
741 Log.d(TAG, "Package not found " + e.getMessage());
742 return true;
743 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800744 }
745
746 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700747 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
748 Preconditions.checkNotNull(account, "account cannot be null");
749 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800750 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700751 int userId = UserHandle.getCallingUserId();
752 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800753 && !isSystemUid(callingUid)) {
754 String msg = String.format(
755 "uid %s cannot get secrets for accounts of type: %s",
756 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700757 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800758 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700759 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700760 long identityToken = clearCallingIdentity();
761 try {
762 UserAccounts accounts = getUserAccounts(userId);
763 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700764 accounts);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700765 } finally {
766 restoreCallingIdentity(identityToken);
767 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700768 }
769
sunjian066aa5e2017-06-05 12:16:59 -0700770 private boolean isVisible(int visibility) {
771 return visibility == AccountManager.VISIBILITY_VISIBLE ||
772 visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
773 }
774
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700775 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800776 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700777 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800778 * @param account Account to update visibility.
779 * @param packageName Package name for which visibility is updated.
780 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800781 * @param notify if the flag is set applications will get notification about visibility change
782 * @param accounts UserAccount that currently hosts the account and application
783 *
784 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700785 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800786 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800787 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700788 synchronized (accounts.dbLock) {
789 synchronized (accounts.cacheLock) {
790 Map<String, Integer> packagesToVisibility;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700791 List<String> accountRemovedReceivers;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700792 if (notify) {
793 if (isSpecialPackageKey(packageName)) {
794 packagesToVisibility =
795 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700796 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700797 } else {
798 if (!packageExistsForUser(packageName, accounts.userId)) {
799 return false; // package is not installed.
800 }
801 packagesToVisibility = new HashMap<>();
802 packagesToVisibility.put(packageName,
803 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700804 accountRemovedReceivers = new ArrayList<>();
805 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
806 accountRemovedReceivers.add(packageName);
807 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700808 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800809 } else {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700810 // Notifications will not be send - only used during add account.
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700811 if (!isSpecialPackageKey(packageName) &&
812 !packageExistsForUser(packageName, accounts.userId)) {
813 // package is not installed and not meta value.
814 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100815 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700816 packagesToVisibility = Collections.emptyMap();
817 accountRemovedReceivers = Collections.emptyList();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800818 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700819
820 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800821 return false;
822 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800823
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700824 if (notify) {
825 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
826 .entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -0700827 int oldVisibility = packageToVisibility.getValue();
828 int currentVisibility =
829 resolveAccountVisibility(account, packageName, accounts);
830 if (isVisible(oldVisibility) != isVisible(currentVisibility)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700831 notifyPackage(packageToVisibility.getKey(), accounts);
832 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700833 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700834 for (String packageNameToNotify : accountRemovedReceivers) {
835 sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
836 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700837 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700838 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700839 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800840 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700841 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700842 }
843
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700844 // Update account visibility in cache and database.
845 private boolean updateAccountVisibilityLocked(Account account, String packageName,
846 int newVisibility, UserAccounts accounts) {
847 final long accountId = accounts.accountsDb.findDeAccountId(account);
848 if (accountId < 0) {
849 return false;
850 }
851
852 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
853 try {
854 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
855 newVisibility)) {
856 return false;
857 }
858 } finally {
859 StrictMode.setThreadPolicy(oldPolicy);
860 }
861 Map<String, Integer> accountVisibility =
862 getPackagesAndVisibilityForAccountLocked(account, accounts);
863 accountVisibility.put(packageName, newVisibility);
864 return true;
865 }
866
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700867 @Override
868 public void registerAccountListener(String[] accountTypes, String opPackageName) {
869 int callingUid = Binder.getCallingUid();
870 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700871
872 int userId = UserHandle.getCallingUserId();
873 long identityToken = clearCallingIdentity();
874 try {
875 UserAccounts accounts = getUserAccounts(userId);
876 registerAccountListener(accountTypes, opPackageName, accounts);
877 } finally {
878 restoreCallingIdentity(identityToken);
879 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800880 }
881
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700882 private void registerAccountListener(String[] accountTypes, String opPackageName,
883 UserAccounts accounts) {
884 synchronized (accounts.mReceiversForType) {
885 if (accountTypes == null) {
886 // null for any type
887 accountTypes = new String[] {null};
888 }
889 for (String type : accountTypes) {
890 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
891 if (receivers == null) {
892 receivers = new HashMap<>();
893 accounts.mReceiversForType.put(type, receivers);
894 }
895 Integer cnt = receivers.get(opPackageName);
896 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800897 }
898 }
899 }
900
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700901 @Override
902 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
903 int callingUid = Binder.getCallingUid();
904 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700905 int userId = UserHandle.getCallingUserId();
906 long identityToken = clearCallingIdentity();
907 try {
908 UserAccounts accounts = getUserAccounts(userId);
909 unregisterAccountListener(accountTypes, opPackageName, accounts);
910 } finally {
911 restoreCallingIdentity(identityToken);
912 }
913 }
914
915 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
916 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700917 synchronized (accounts.mReceiversForType) {
918 if (accountTypes == null) {
919 // null for any type
920 accountTypes = new String[] {null};
921 }
922 for (String type : accountTypes) {
923 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
924 if (receivers == null || receivers.get(opPackageName) == null) {
925 throw new IllegalArgumentException("attempt to unregister wrong receiver");
926 }
927 Integer cnt = receivers.get(opPackageName);
928 if (cnt == 1) {
929 receivers.remove(opPackageName);
930 } else {
931 receivers.put(opPackageName, cnt - 1);
932 }
933 }
934 }
935 }
936
937 // Send notification to all packages which can potentially see the account
938 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
939 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700940
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700941 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700942 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
943 && (packageToVisibility.getValue()
944 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700945 notifyPackage(packageToVisibility.getKey(), accounts);
946 }
947 }
948 }
949
950 /**
951 * Sends a direct intent to a package, notifying it of account visibility change.
952 *
953 * @param packageName to send Account to
954 * @param accounts UserAccount that currently hosts the account
955 */
956 private void notifyPackage(String packageName, UserAccounts accounts) {
957 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
958 intent.setPackage(packageName);
959 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
960 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
961 }
962
963 // Returns a map from package name to visibility, for packages subscribed
964 // to notifications about any account type, or type of provided account
965 // account type or all types.
966 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
967 Set<String> packages = new HashSet<>();
968 synchronized (accounts.mReceiversForType) {
969 for (String type : new String[] {account.type, null}) {
970 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
971 if (receivers != null) {
972 packages.addAll(receivers.keySet());
973 }
974 }
975 }
976 Map<String, Integer> result = new HashMap<>();
977 for (String packageName : packages) {
978 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
979 }
980 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800981 }
982
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700983 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
984 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
985 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
986 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
987 List<ResolveInfo> receivers =
988 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
989 List<String> result = new ArrayList<>();
990 if (receivers == null) {
991 return result;
992 }
993 for (ResolveInfo resolveInfo: receivers) {
994 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
995 int visibility = resolveAccountVisibility(account, packageName, accounts);
996 if (visibility == AccountManager.VISIBILITY_VISIBLE
997 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
998 result.add(packageName);
999 }
1000 }
1001 return result;
1002 }
1003
1004 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
1005 private boolean shouldNotifyPackageOnAccountRemoval(Account account,
1006 String packageName, UserAccounts accounts) {
1007 int visibility = resolveAccountVisibility(account, packageName, accounts);
1008 if (visibility != AccountManager.VISIBILITY_VISIBLE
1009 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1010 return false;
1011 }
1012
1013 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1014 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1015 intent.setPackage(packageName);
1016 List<ResolveInfo> receivers =
1017 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1018 return (receivers != null && receivers.size() > 0);
1019 }
1020
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001021 private boolean packageExistsForUser(String packageName, int userId) {
1022 try {
1023 long identityToken = clearCallingIdentity();
1024 try {
1025 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -07001026 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001027 } finally {
1028 restoreCallingIdentity(identityToken);
1029 }
1030 } catch (NameNotFoundException e) {
1031 return false;
1032 }
1033 }
1034
1035 /**
1036 * Returns true if packageName is one of special values.
1037 */
1038 private boolean isSpecialPackageKey(String packageName) {
1039 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1040 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1041 }
1042
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001043 private void sendAccountsChangedBroadcast(int userId) {
1044 Log.i(TAG, "the accounts changed, sending broadcast of "
1045 + ACCOUNTS_CHANGED_INTENT.getAction());
1046 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001047 }
1048
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001049 private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001050 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1051 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001052 intent.setPackage(packageName);
1053 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1054 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001055 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1056 }
1057
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001058 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -07001059 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1060 throws RemoteException {
1061 try {
1062 return super.onTransact(code, data, reply, flags);
1063 } catch (RuntimeException e) {
1064 // The account manager only throws security exceptions, so let's
1065 // log all others.
1066 if (!(e instanceof SecurityException)) {
1067 Slog.wtf(TAG, "Account Manager Crash", e);
1068 }
1069 throw e;
1070 }
1071 }
1072
Amith Yamasani258848d2012-08-10 17:06:33 -07001073 private UserManager getUserManager() {
1074 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -07001075 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -07001076 }
1077 return mUserManager;
1078 }
1079
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001080 /**
1081 * Validate internal set of accounts against installed authenticators for
1082 * given user. Clears cached authenticators before validating.
1083 */
1084 public void validateAccounts(int userId) {
1085 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001086 // Invalidate user-specific cache to make sure we catch any
1087 // removed authenticators.
1088 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1089 }
1090
1091 /**
1092 * Validate internal set of accounts against installed authenticators for
1093 * given user. Clear cached authenticators before validating when requested.
1094 */
1095 private void validateAccountsInternal(
1096 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001097 if (Log.isLoggable(TAG, Log.DEBUG)) {
1098 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001099 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001100 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001101 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001102
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001103 if (invalidateAuthenticatorCache) {
1104 mAuthenticatorCache.invalidateCache(accounts.userId);
1105 }
1106
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001107 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1108 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001109 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001110
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001111 synchronized (accounts.dbLock) {
1112 synchronized (accounts.cacheLock) {
1113 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001114
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001115 // Get a map of stored authenticator types to UID
1116 final AccountsDb accountsDb = accounts.accountsDb;
1117 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1118 // Create a list of authenticator type whose previous uid no longer exists
1119 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1120 SparseBooleanArray knownUids = null;
1121 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1122 String type = authToUidEntry.getKey();
1123 int uid = authToUidEntry.getValue();
1124 Integer knownUid = knownAuth.get(type);
1125 if (knownUid != null && uid == knownUid) {
1126 // Remove it from the knownAuth list if it's unchanged.
1127 knownAuth.remove(type);
1128 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001129 /*
1130 * The authenticator is presently not cached and should only be triggered
1131 * when we think an authenticator has been removed (or is being updated).
1132 * But we still want to check if any data with the associated uid is
1133 * around. This is an (imperfect) signal that the package may be updating.
1134 *
1135 * A side effect of this is that an authenticator sharing a uid with
1136 * multiple apps won't get its credentials wiped as long as some app with
1137 * that uid is still on the device. But I suspect that this is a rare case.
1138 * And it isn't clear to me how an attacker could really exploit that
1139 * feature.
1140 *
1141 * The upshot is that we don't have to worry about accounts getting
1142 * uninstalled while the authenticator's package is being updated.
1143 *
1144 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001145 if (knownUids == null) {
1146 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1147 }
1148 if (!knownUids.get(uid)) {
1149 // The authenticator is not presently available to the cache. And the
1150 // package no longer has a data directory (so we surmise it isn't
1151 // updating). So purge its data from the account databases.
1152 obsoleteAuthType.add(type);
1153 // And delete it from the TABLE_META
1154 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1155 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001156 }
1157 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001158
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001159 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1160 // been re-enabled (after being updated for example), then we just overwrite the old
1161 // values.
1162 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1163 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1164 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001165
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001166 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1167 try {
1168 accounts.accountCache.clear();
1169 final HashMap<String, ArrayList<String>> accountNamesByType
1170 = new LinkedHashMap<>();
1171 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1172 final long accountId = accountEntry.getKey();
1173 final Account account = accountEntry.getValue();
1174 if (obsoleteAuthType.contains(account.type)) {
1175 Slog.w(TAG, "deleting account " + account.name + " because type "
1176 + account.type
1177 + "'s registered authenticator no longer exist.");
1178 Map<String, Integer> packagesToVisibility =
1179 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001180 List<String> accountRemovedReceivers =
1181 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001182 accountsDb.beginTransaction();
1183 try {
1184 accountsDb.deleteDeAccount(accountId);
1185 // Also delete from CE table if user is unlocked; if user is
1186 // currently locked the account will be removed later by
1187 // syncDeCeAccountsLocked
1188 if (userUnlocked) {
1189 accountsDb.deleteCeAccount(accountId);
1190 }
1191 accountsDb.setTransactionSuccessful();
1192 } finally {
1193 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001194 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001195 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001196
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001197 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1198 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001199
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001200 accounts.userDataCache.remove(account);
1201 accounts.authTokenCache.remove(account);
1202 accounts.accountTokenCaches.remove(account);
1203 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001204
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001205 for (Entry<String, Integer> packageToVisibility :
1206 packagesToVisibility.entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -07001207 if (isVisible(packageToVisibility.getValue())) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001208 notifyPackage(packageToVisibility.getKey(), accounts);
1209 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001210 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001211 for (String packageName : accountRemovedReceivers) {
1212 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1213 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001214 } else {
1215 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1216 if (accountNames == null) {
1217 accountNames = new ArrayList<>();
1218 accountNamesByType.put(account.type, accountNames);
1219 }
1220 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001221 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001222 }
1223 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1224 final String accountType = cur.getKey();
1225 final ArrayList<String> accountNames = cur.getValue();
1226 final Account[] accountsForType = new Account[accountNames.size()];
1227 for (int i = 0; i < accountsForType.length; i++) {
1228 accountsForType[i] = new Account(accountNames.get(i), accountType,
1229 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001230 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001231 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001232 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001233 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1234 } finally {
1235 if (accountDeleted) {
1236 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001237 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001238 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001239 }
1240 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001241 }
1242
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001243 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1244 // Get the UIDs of all apps that might have data on the device. We want
1245 // to preserve user data if the app might otherwise be storing data.
1246 List<PackageInfo> pkgsWithData =
1247 mPackageManager.getInstalledPackagesAsUser(
1248 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1249 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1250 for (PackageInfo pkgInfo : pkgsWithData) {
1251 if (pkgInfo.applicationInfo != null
1252 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1253 knownUids.put(pkgInfo.applicationInfo.uid, true);
1254 }
1255 }
1256 return knownUids;
1257 }
1258
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001259 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001260 Context context,
1261 int userId) {
1262 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001263 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1264 }
1265
1266 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1267 IAccountAuthenticatorCache authCache,
1268 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001269 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001270 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1271 .getAllServices(userId)) {
1272 knownAuth.put(service.type.type, service.uid);
1273 }
1274 return knownAuth;
1275 }
1276
Amith Yamasani04e0d262012-02-14 11:50:53 -08001277 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001278 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001279 }
1280
1281 protected UserAccounts getUserAccounts(int userId) {
1282 synchronized (mUsers) {
1283 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001284 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001285 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001286 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1287 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001288 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001289 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001290 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001291 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001292 validateAccounts = true;
1293 }
1294 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001295 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001296 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001297 synchronized (accounts.dbLock) {
1298 synchronized (accounts.cacheLock) {
1299 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1300 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1301 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001302 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001303 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001304 }
1305 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001306 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001307 }
1308 return accounts;
1309 }
1310 }
1311
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001312 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1313 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001314 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001315 if (!accountsToRemove.isEmpty()) {
1316 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1317 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001318 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1319 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001320
1321 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001322 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001323 }
1324 }
1325 }
1326
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001327 private void purgeOldGrantsAll() {
1328 synchronized (mUsers) {
1329 for (int i = 0; i < mUsers.size(); i++) {
1330 purgeOldGrants(mUsers.valueAt(i));
1331 }
1332 }
1333 }
1334
1335 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001336 synchronized (accounts.dbLock) {
1337 synchronized (accounts.cacheLock) {
1338 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1339 for (int uid : uids) {
1340 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1341 if (packageExists) {
1342 continue;
1343 }
1344 Log.d(TAG, "deleting grants for UID " + uid
1345 + " because its package is no longer installed");
1346 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001347 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001348 }
1349 }
1350 }
1351
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001352 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001353 if (isSpecialPackageKey(packageName)) {
1354 return;
1355 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001356 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001357 int numberOfUsers = mUsers.size();
1358 for (int i = 0; i < numberOfUsers; i++) {
1359 UserAccounts accounts = mUsers.valueAt(i);
1360 try {
1361 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1362 } catch (NameNotFoundException e) {
1363 // package does not exist - remove visibility values
1364 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001365 synchronized (accounts.dbLock) {
1366 synchronized (accounts.cacheLock) {
1367 for (Account account : accounts.visibilityCache.keySet()) {
1368 Map<String, Integer> accountVisibility =
1369 getPackagesAndVisibilityForAccountLocked(account, accounts);
1370 accountVisibility.remove(packageName);
1371 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001372 }
1373 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001374 }
1375 }
1376 }
1377 }
1378
Fyodor Kupolov945c97e2017-06-21 17:45:19 -07001379 private void purgeUserData(int userId) {
Amith Yamasani13593602012-03-22 16:16:17 -07001380 UserAccounts accounts;
1381 synchronized (mUsers) {
1382 accounts = mUsers.get(userId);
1383 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001384 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001385 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001386 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001387 synchronized (accounts.dbLock) {
1388 synchronized (accounts.cacheLock) {
Fyodor Kupolov56e158f2017-05-23 16:41:51 -07001389 accounts.statementForLogging.close();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001390 accounts.accountsDb.close();
1391 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001392 }
Amith Yamasani13593602012-03-22 16:16:17 -07001393 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001394 }
1395
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001396 @VisibleForTesting
1397 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001398 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1399 }
1400
1401 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001402 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1403 Log.v(TAG, "onUserUnlocked " + userId);
1404 }
1405 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001406 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001407 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001408 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001409 syncSharedAccounts(userId);
1410 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001411
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001412 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001413 // Check if there's a shared account that needs to be created as an account
1414 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1415 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001416 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001417 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001418 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001419 : UserHandle.USER_SYSTEM;
1420 if (parentUserId < 0) {
1421 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1422 return;
1423 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001424 for (Account sa : sharedAccounts) {
1425 if (ArrayUtils.contains(accounts, sa)) continue;
1426 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001427 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001428 }
1429 }
1430
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001431 @Override
1432 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001433 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001434 }
1435
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001436 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001437 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001438 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001439 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1440 Log.v(TAG, "getPassword: " + account
1441 + ", caller's uid " + Binder.getCallingUid()
1442 + ", pid " + Binder.getCallingPid());
1443 }
Fred Quintana382601f2010-03-25 12:25:10 -07001444 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001445 int userId = UserHandle.getCallingUserId();
1446 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001447 String msg = String.format(
1448 "uid %s cannot get secrets for accounts of type: %s",
1449 callingUid,
1450 account.type);
1451 throw new SecurityException(msg);
1452 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001453 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001454 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001455 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001456 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001457 } finally {
1458 restoreCallingIdentity(identityToken);
1459 }
1460 }
1461
Amith Yamasani04e0d262012-02-14 11:50:53 -08001462 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001463 if (account == null) {
1464 return null;
1465 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001466 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001467 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1468 return null;
1469 }
Fred Quintana31957f12009-10-21 13:43:10 -07001470
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001471 synchronized (accounts.dbLock) {
1472 synchronized (accounts.cacheLock) {
1473 return accounts.accountsDb
1474 .findAccountPasswordByNameAndType(account.name, account.type);
1475 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001476 }
1477 }
1478
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001479 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001480 public String getPreviousName(Account account) {
1481 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1482 Log.v(TAG, "getPreviousName: " + account
1483 + ", caller's uid " + Binder.getCallingUid()
1484 + ", pid " + Binder.getCallingPid());
1485 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001486 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001487 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001488 long identityToken = clearCallingIdentity();
1489 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001490 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001491 return readPreviousNameInternal(accounts, account);
1492 } finally {
1493 restoreCallingIdentity(identityToken);
1494 }
1495 }
1496
1497 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1498 if (account == null) {
1499 return null;
1500 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001501 synchronized (accounts.dbLock) {
1502 synchronized (accounts.cacheLock) {
1503 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1504 if (previousNameRef == null) {
1505 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1506 previousNameRef = new AtomicReference<>(previousName);
1507 accounts.previousNameCache.put(account, previousNameRef);
1508 return previousName;
1509 } else {
1510 return previousNameRef.get();
1511 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001512 }
1513 }
1514 }
1515
1516 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001517 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001518 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001519 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001520 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1521 account, key, callingUid, Binder.getCallingPid());
1522 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001523 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001524 Preconditions.checkNotNull(account, "account cannot be null");
1525 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001526 int userId = UserHandle.getCallingUserId();
1527 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001528 String msg = String.format(
1529 "uid %s cannot get user data for accounts of type: %s",
1530 callingUid,
1531 account.type);
1532 throw new SecurityException(msg);
1533 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001534 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001535 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1536 return null;
1537 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001538 long identityToken = clearCallingIdentity();
1539 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001540 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001541 if (!accountExistsCache(accounts, account)) {
1542 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001543 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001544 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001545 } finally {
1546 restoreCallingIdentity(identityToken);
1547 }
1548 }
1549
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001550 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001551 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001552 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001553 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1554 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001555 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001556 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001557 + ", pid " + Binder.getCallingPid());
1558 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001559 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001560 if (isCrossUser(callingUid, userId)) {
1561 throw new SecurityException(
1562 String.format(
1563 "User %s tying to get authenticator types for %s" ,
1564 UserHandle.getCallingUserId(),
1565 userId));
1566 }
1567
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001568 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001569 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001570 return getAuthenticatorTypesInternal(userId);
1571
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001572 } finally {
1573 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001574 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001575 }
1576
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001577 /**
1578 * Should only be called inside of a clearCallingIdentity block.
1579 */
1580 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001581 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001582 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1583 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1584 AuthenticatorDescription[] types =
1585 new AuthenticatorDescription[authenticatorCollection.size()];
1586 int i = 0;
1587 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1588 : authenticatorCollection) {
1589 types[i] = authenticator.type;
1590 i++;
1591 }
1592 return types;
1593 }
1594
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001595 private boolean isCrossUser(int callingUid, int userId) {
1596 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001597 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001598 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001599 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1600 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001601 }
1602
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001603 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001604 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001605 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001606 }
1607
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001608 @Override
1609 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001610 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001611 int callingUid = Binder.getCallingUid();
1612 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1613 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001614 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001615 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001616 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1617 final UserAccounts toAccounts = getUserAccounts(userTo);
1618 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001619 if (response != null) {
1620 Bundle result = new Bundle();
1621 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1622 try {
1623 response.onResult(result);
1624 } catch (RemoteException e) {
1625 Slog.w(TAG, "Failed to report error back to the client." + e);
1626 }
1627 }
1628 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001629 }
1630
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001631 Slog.d(TAG, "Copying account " + account.name
1632 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001633 long identityToken = clearCallingIdentity();
1634 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001635 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001636 false /* stripAuthTokenFromResult */, account.name,
1637 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001638 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001639 protected String toDebugString(long now) {
1640 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1641 + ", " + account.type;
1642 }
1643
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001644 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001645 public void run() throws RemoteException {
1646 mAuthenticator.getAccountCredentialsForCloning(this, account);
1647 }
1648
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001649 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001650 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001651 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001652 if (result != null
1653 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1654 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001655 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001656 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001657 super.onResult(result);
1658 }
1659 }
1660 }.bind();
1661 } finally {
1662 restoreCallingIdentity(identityToken);
1663 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001664 }
1665
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001666 @Override
1667 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001668 final int callingUid = Binder.getCallingUid();
1669 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1670 String msg = String.format(
1671 "accountAuthenticated( account: %s, callerUid: %s)",
1672 account,
1673 callingUid);
1674 Log.v(TAG, msg);
1675 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001676 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001677 int userId = UserHandle.getCallingUserId();
1678 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001679 String msg = String.format(
1680 "uid %s cannot notify authentication for accounts of type: %s",
1681 callingUid,
1682 account.type);
1683 throw new SecurityException(msg);
1684 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001685
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001686 if (!canUserModifyAccounts(userId, callingUid) ||
1687 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001688 return false;
1689 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001690
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001691 long identityToken = clearCallingIdentity();
1692 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001693 UserAccounts accounts = getUserAccounts(userId);
1694 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001695 } finally {
1696 restoreCallingIdentity(identityToken);
1697 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001698 }
1699
1700 private boolean updateLastAuthenticatedTime(Account account) {
1701 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001702 synchronized (accounts.dbLock) {
1703 synchronized (accounts.cacheLock) {
1704 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1705 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001706 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001707 }
1708
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001709 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001710 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1711 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001712 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001713 long id = clearCallingIdentity();
1714 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001715 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001716 false /* stripAuthTokenFromResult */, account.name,
1717 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001718 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001719 protected String toDebugString(long now) {
1720 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1721 + ", " + account.type;
1722 }
1723
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001724 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001725 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001726 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001727 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1728 if (acc.equals(account)) {
1729 mAuthenticator.addAccountFromCredentials(
1730 this, account, accountCredentials);
1731 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001732 }
1733 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001734 }
1735
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001736 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001737 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001738 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001739 // TODO: Anything to do if if succedded?
1740 // TODO: If it failed: Show error notification? Should we remove the shadow
1741 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001742 // TODO: what we do with the visibility?
1743
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001744 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001745 }
1746
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001747 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001748 public void onError(int errorCode, String errorMessage) {
1749 super.onError(errorCode, errorMessage);
1750 // TODO: Show error notification to user
1751 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1752 }
1753
1754 }.bind();
1755 } finally {
1756 restoreCallingIdentity(id);
1757 }
1758 }
1759
Amith Yamasani04e0d262012-02-14 11:50:53 -08001760 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001761 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001762 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001763 if (account == null) {
1764 return false;
1765 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001766 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001767 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1768 + " is locked. callingUid=" + callingUid);
1769 return false;
1770 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001771 synchronized (accounts.dbLock) {
1772 synchronized (accounts.cacheLock) {
1773 accounts.accountsDb.beginTransaction();
1774 try {
1775 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1776 Log.w(TAG, "insertAccountIntoDatabase: " + account
1777 + ", skipping since the account already exists");
1778 return false;
1779 }
1780 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1781 if (accountId < 0) {
1782 Log.w(TAG, "insertAccountIntoDatabase: " + account
1783 + ", skipping the DB insert failed");
1784 return false;
1785 }
1786 // Insert into DE table
1787 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1788 Log.w(TAG, "insertAccountIntoDatabase: " + account
1789 + ", skipping the DB insert failed");
1790 return false;
1791 }
1792 if (extras != null) {
1793 for (String key : extras.keySet()) {
1794 final String value = extras.getString(key);
1795 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1796 Log.w(TAG, "insertAccountIntoDatabase: " + account
1797 + ", skipping since insertExtra failed for key " + key);
1798 return false;
1799 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001800 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001801 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001802
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001803 if (packageToVisibility != null) {
1804 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1805 setAccountVisibility(account, entry.getKey() /* package */,
1806 entry.getValue() /* visibility */, false /* notify */,
1807 accounts);
1808 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001809 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001810 accounts.accountsDb.setTransactionSuccessful();
1811
1812 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1813 accountId,
1814 accounts, callingUid);
1815
1816 insertAccountIntoCacheLocked(accounts, account);
1817 } finally {
1818 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001819 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001820 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001821 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001822 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1823 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001824 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001825
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001826 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001827 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1828 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001829
Amith Yamasani5be347b2013-03-31 17:44:31 -07001830 return true;
1831 }
1832
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001833 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001834 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001835 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001836 }
1837 }
1838
Amith Yamasani5be347b2013-03-31 17:44:31 -07001839 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001840 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001841 * running, then clone the account too.
1842 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001843 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001844 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001845 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001846 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001847 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001848 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001849 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001850 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001851 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001852 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001853 }
1854 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001855 }
1856 }
1857
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001858 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001859 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001860 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001861 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001862 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001863 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1864 Log.v(TAG, "hasFeatures: " + account
1865 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001866 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001867 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001868 + ", pid " + Binder.getCallingPid());
1869 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001870 Preconditions.checkArgument(account != null, "account cannot be null");
1871 Preconditions.checkArgument(response != null, "response cannot be null");
1872 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001873 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001874 checkReadAccountsPermitted(callingUid, account.type, userId,
1875 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001876
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001877 long identityToken = clearCallingIdentity();
1878 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001879 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001880 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001881 } finally {
1882 restoreCallingIdentity(identityToken);
1883 }
1884 }
1885
1886 private class TestFeaturesSession extends Session {
1887 private final String[] mFeatures;
1888 private final Account mAccount;
1889
Amith Yamasani04e0d262012-02-14 11:50:53 -08001890 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001891 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001892 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001893 true /* stripAuthTokenFromResult */, account.name,
1894 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001895 mFeatures = features;
1896 mAccount = account;
1897 }
1898
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001899 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001900 public void run() throws RemoteException {
1901 try {
1902 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1903 } catch (RemoteException e) {
1904 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1905 }
1906 }
1907
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001908 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001909 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001910 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001911 IAccountManagerResponse response = getResponseAndClose();
1912 if (response != null) {
1913 try {
1914 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001915 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001916 return;
1917 }
Fred Quintana56285a62010-12-02 14:20:51 -08001918 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1919 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1920 + response);
1921 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001922 final Bundle newResult = new Bundle();
1923 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1924 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1925 response.onResult(newResult);
1926 } catch (RemoteException e) {
1927 // if the caller is dead then there is no one to care about remote exceptions
1928 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1929 Log.v(TAG, "failure while notifying response", e);
1930 }
1931 }
1932 }
1933 }
1934
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001935 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001936 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001937 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001938 + ", " + mAccount
1939 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1940 }
1941 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001942
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001943 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001944 public void renameAccount(
1945 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001946 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001947 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1948 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001949 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001950 + ", pid " + Binder.getCallingPid());
1951 }
1952 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001953 int userId = UserHandle.getCallingUserId();
1954 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001955 String msg = String.format(
1956 "uid %s cannot rename accounts of type: %s",
1957 callingUid,
1958 accountToRename.type);
1959 throw new SecurityException(msg);
1960 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001961 long identityToken = clearCallingIdentity();
1962 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001963 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001964 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001965 Bundle result = new Bundle();
1966 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1967 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001968 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1969 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001970 try {
1971 response.onResult(result);
1972 } catch (RemoteException e) {
1973 Log.w(TAG, e.getMessage());
1974 }
1975 } finally {
1976 restoreCallingIdentity(identityToken);
1977 }
1978 }
1979
1980 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001981 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001982 Account resultAccount = null;
1983 /*
1984 * Cancel existing notifications. Let authenticators
1985 * re-post notifications as required. But we don't know if
1986 * the authenticators have bound their notifications to
1987 * now stale account name data.
1988 *
1989 * With a rename api, we might not need to do this anymore but it
1990 * shouldn't hurt.
1991 */
1992 cancelNotification(
1993 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04001994 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001995 synchronized(accounts.credentialsPermissionNotificationIds) {
1996 for (Pair<Pair<Account, String>, Integer> pair:
1997 accounts.credentialsPermissionNotificationIds.keySet()) {
1998 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04001999 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002000 cancelNotification(id, new UserHandle(accounts.userId));
2001 }
2002 }
2003 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002004 synchronized (accounts.dbLock) {
2005 synchronized (accounts.cacheLock) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002006 List<String> accountRemovedReceivers =
2007 getAccountRemovedReceivers(accountToRename, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002008 accounts.accountsDb.beginTransaction();
2009 Account renamedAccount = new Account(newName, accountToRename.type);
2010 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
2011 Log.e(TAG, "renameAccount failed - account with new name already exists");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002012 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002013 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002014 try {
2015 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2016 if (accountId >= 0) {
2017 accounts.accountsDb.renameCeAccount(accountId, newName);
2018 if (accounts.accountsDb.renameDeAccount(
2019 accountId, newName, accountToRename.name)) {
2020 accounts.accountsDb.setTransactionSuccessful();
2021 } else {
2022 Log.e(TAG, "renameAccount failed");
2023 return null;
2024 }
2025 } else {
2026 Log.e(TAG, "renameAccount failed - old account does not exist");
2027 return null;
2028 }
2029 } finally {
2030 accounts.accountsDb.endTransaction();
2031 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002032 /*
2033 * Database transaction was successful. Clean up cached
2034 * data associated with the account in the user profile.
2035 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002036 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002037 /*
2038 * Extract the data and token caches before removing the
2039 * old account to preserve the user data associated with
2040 * the account.
2041 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002042 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2043 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2044 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2045 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002046 /*
2047 * Update the cached data associated with the renamed
2048 * account.
2049 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002050 accounts.userDataCache.put(renamedAccount, tmpData);
2051 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2052 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2053 accounts.previousNameCache.put(
2054 renamedAccount,
2055 new AtomicReference<>(accountToRename.name));
2056 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002057
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002058 int parentUserId = accounts.userId;
2059 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002060 /*
2061 * Owner or system user account was renamed, rename the account for
2062 * those users with which the account was shared.
2063 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002064 List<UserInfo> users = getUserManager().getUsers(true);
2065 for (UserInfo user : users) {
2066 if (user.isRestricted()
2067 && (user.restrictedProfileParentId == parentUserId)) {
2068 renameSharedAccountAsUser(accountToRename, newName, user.id);
2069 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002070 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002071 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002072
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002073 sendNotificationAccountUpdated(resultAccount, accounts);
2074 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002075 for (String packageName : accountRemovedReceivers) {
2076 sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2077 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002078 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002079 }
2080 return resultAccount;
2081 }
2082
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002083 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002084 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002085 return userInfo != null && userInfo.canHaveProfile();
2086 }
2087
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002088 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002089 public void removeAccount(IAccountManagerResponse response, Account account,
2090 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002091 removeAccountAsUser(
2092 response,
2093 account,
2094 expectActivityLaunch,
2095 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002096 }
2097
2098 @Override
2099 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002100 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002101 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002102 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2103 Log.v(TAG, "removeAccount: " + account
2104 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002105 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002106 + ", pid " + Binder.getCallingPid()
2107 + ", for user id " + userId);
2108 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002109 Preconditions.checkArgument(account != null, "account cannot be null");
2110 Preconditions.checkArgument(response != null, "response cannot be null");
2111
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002112 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002113 if (isCrossUser(callingUid, userId)) {
2114 throw new SecurityException(
2115 String.format(
2116 "User %s tying remove account for %s" ,
2117 UserHandle.getCallingUserId(),
2118 userId));
2119 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002120 /*
Alex Chauf788f9c2017-12-08 15:16:46 +00002121 * Only the system, authenticator or profile owner should be allowed to remove accounts for
2122 * that authenticator. This will let users remove accounts (via Settings in the system) but
2123 * not arbitrary applications (like competing authenticators).
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002124 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002125 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002126 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
Alex Chauf788f9c2017-12-08 15:16:46 +00002127 && !isSystemUid(callingUid)
2128 && !isProfileOwner(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002129 String msg = String.format(
2130 "uid %s cannot remove accounts of type: %s",
2131 callingUid,
2132 account.type);
2133 throw new SecurityException(msg);
2134 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002135 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002136 try {
2137 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2138 "User cannot modify accounts");
2139 } catch (RemoteException re) {
2140 }
2141 return;
2142 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002143 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002144 try {
2145 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2146 "User cannot modify accounts of this type (policy).");
2147 } catch (RemoteException re) {
2148 }
2149 return;
2150 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002151 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002152 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002153 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002154 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002155 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002156 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002157 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002158 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002159 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002160 }
2161 }
2162 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002163 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002164 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002165 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2166 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002167 accountId,
2168 accounts,
2169 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002170 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002171 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2172 } finally {
2173 restoreCallingIdentity(identityToken);
2174 }
2175 }
2176
2177 @Override
2178 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002179 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002180 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2181 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002182 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002183 + ", pid " + Binder.getCallingPid());
2184 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002185 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002186 if (account == null) {
2187 /*
2188 * Null accounts should result in returning false, as per
2189 * AccountManage.addAccountExplicitly(...) java doc.
2190 */
2191 Log.e(TAG, "account is null");
2192 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002193 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002194 String msg = String.format(
Brandon Weeks9e4e96d2017-08-24 15:24:16 -07002195 "uid %s cannot explicitly remove accounts of type: %s",
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002196 callingUid,
2197 account.type);
2198 throw new SecurityException(msg);
2199 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002200 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002201 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002202 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002203 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2204 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002205 accountId,
2206 accounts,
2207 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002208 long identityToken = clearCallingIdentity();
2209 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002210 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002211 } finally {
2212 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002213 }
Fred Quintana60307342009-03-24 22:48:12 -07002214 }
2215
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002216 private class RemoveAccountSession extends Session {
2217 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002218 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002219 Account account, boolean expectActivityLaunch) {
2220 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002221 true /* stripAuthTokenFromResult */, account.name,
2222 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002223 mAccount = account;
2224 }
2225
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002226 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002227 protected String toDebugString(long now) {
2228 return super.toDebugString(now) + ", removeAccount"
2229 + ", account " + mAccount;
2230 }
2231
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002232 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002233 public void run() throws RemoteException {
2234 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2235 }
2236
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002237 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002238 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002239 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002240 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2241 && !result.containsKey(AccountManager.KEY_INTENT)) {
2242 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002243 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002244 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002245 }
2246 IAccountManagerResponse response = getResponseAndClose();
2247 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002248 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2249 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2250 + response);
2251 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002252 try {
tiansiming5330b5a2017-10-13 10:57:25 +08002253 response.onResult(result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002254 } catch (RemoteException e) {
tiansiming5330b5a2017-10-13 10:57:25 +08002255 Slog.e(TAG, "Error calling onResult()", e);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002256 }
2257 }
2258 }
2259 super.onResult(result);
2260 }
2261 }
2262
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002263 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002264 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002265 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002266 }
2267
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002268 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002269 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002270 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002271 if (!userUnlocked) {
2272 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2273 + " is still locked. CE data will be removed later");
2274 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002275 synchronized (accounts.dbLock) {
2276 synchronized (accounts.cacheLock) {
2277 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2278 accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002279 List<String> accountRemovedReceivers =
2280 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002281 accounts.accountsDb.beginTransaction();
2282 // Set to a dummy value, this will only be used if the database
2283 // transaction succeeds.
2284 long accountId = -1;
2285 try {
2286 accountId = accounts.accountsDb.findDeAccountId(account);
2287 if (accountId >= 0) {
2288 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002289 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002290 // always delete from CE table if CE storage is available
2291 // DE account could be removed while CE was locked
2292 if (userUnlocked) {
2293 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2294 if (ceAccountId >= 0) {
2295 accounts.accountsDb.deleteCeAccount(ceAccountId);
2296 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002297 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002298 accounts.accountsDb.setTransactionSuccessful();
2299 } finally {
2300 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002301 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002302 if (isChanged) {
2303 removeAccountFromCacheLocked(accounts, account);
2304 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2305 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002306 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2307 || (packageToVisibility.getValue()
2308 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002309 notifyPackage(packageToVisibility.getKey(), accounts);
2310 }
2311 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002312
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002313 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2314 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002315 for (String packageName : accountRemovedReceivers) {
2316 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2317 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002318 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2319 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2320 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2321 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002322 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002323 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002324 long id = Binder.clearCallingIdentity();
2325 try {
2326 int parentUserId = accounts.userId;
2327 if (canHaveProfile(parentUserId)) {
2328 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002329 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002330 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002331 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002332 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002333 }
2334 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002335 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002336 } finally {
2337 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002338 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002339
2340 if (isChanged) {
2341 synchronized (accounts.credentialsPermissionNotificationIds) {
2342 for (Pair<Pair<Account, String>, Integer> key
2343 : accounts.credentialsPermissionNotificationIds.keySet()) {
2344 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002345 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002346 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002347 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002348 account, uid, false));
2349 }
2350 }
2351 }
2352 }
2353
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002354 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002355 }
2356
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002357 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002358 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002359 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002360 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2361 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002362 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2363 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002364 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002365 + ", pid " + Binder.getCallingPid());
2366 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002367 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002368 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002369 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002370 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002371 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002372 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002373 accounts.accountsDb.beginTransaction();
2374 try {
2375 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2376 accounts.accountsDb.setTransactionSuccessful();
2377 } finally {
2378 accounts.accountsDb.endTransaction();
2379 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002380 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002381 for (Pair<Account, String> tokenInfo : deletedTokens) {
2382 Account act = tokenInfo.first;
2383 String tokenType = tokenInfo.second;
2384 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002385 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002386 // wipe out cached token in memory.
2387 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002388 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002389 }
Fred Quintana60307342009-03-24 22:48:12 -07002390 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002391 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002392 }
2393 }
2394
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002395 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002396 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002397 // TODO Move to AccountsDB
2398 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002399 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002400
Fred Quintana33269202009-04-20 16:05:10 -07002401 try {
2402 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002403 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002404 String accountName = cursor.getString(1);
2405 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002406 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002407 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002408 }
Fred Quintana33269202009-04-20 16:05:10 -07002409 } finally {
2410 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002411 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002412 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002413 }
2414
Carlos Valdivia91979be2015-05-22 14:11:35 -07002415 private void saveCachedToken(
2416 UserAccounts accounts,
2417 Account account,
2418 String callerPkg,
2419 byte[] callerSigDigest,
2420 String tokenType,
2421 String token,
2422 long expiryMillis) {
2423
2424 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2425 return;
2426 }
2427 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002428 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002429 synchronized (accounts.cacheLock) {
2430 accounts.accountTokenCaches.put(
2431 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002432 }
2433 }
2434
Amith Yamasani04e0d262012-02-14 11:50:53 -08002435 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2436 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002437 if (account == null || type == null) {
2438 return false;
2439 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002440 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002441 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002442 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002443 accounts.accountsDb.beginTransaction();
2444 boolean updateCache = false;
2445 try {
2446 long accountId = accounts.accountsDb.findDeAccountId(account);
2447 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002448 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002449 }
2450 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2451 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2452 accounts.accountsDb.setTransactionSuccessful();
2453 updateCache = true;
2454 return true;
2455 }
2456 return false;
2457 } finally {
2458 accounts.accountsDb.endTransaction();
2459 if (updateCache) {
2460 synchronized (accounts.cacheLock) {
2461 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2462 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002463 }
Fred Quintana33269202009-04-20 16:05:10 -07002464 }
Fred Quintana60307342009-03-24 22:48:12 -07002465 }
2466 }
2467
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002468 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002469 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002470 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002471 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2472 Log.v(TAG, "peekAuthToken: " + account
2473 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002474 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002475 + ", pid " + Binder.getCallingPid());
2476 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002477 Preconditions.checkNotNull(account, "account cannot be null");
2478 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002479 int userId = UserHandle.getCallingUserId();
2480 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002481 String msg = String.format(
2482 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2483 callingUid,
2484 account.type);
2485 throw new SecurityException(msg);
2486 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002487 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002488 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2489 + callingUid);
2490 return null;
2491 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002492 long identityToken = clearCallingIdentity();
2493 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002494 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002495 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002496 } finally {
2497 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002498 }
Fred Quintana60307342009-03-24 22:48:12 -07002499 }
2500
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002501 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002502 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002503 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002504 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2505 Log.v(TAG, "setAuthToken: " + account
2506 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002507 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002508 + ", pid " + Binder.getCallingPid());
2509 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002510 Preconditions.checkNotNull(account, "account cannot be null");
2511 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002512 int userId = UserHandle.getCallingUserId();
2513 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002514 String msg = String.format(
2515 "uid %s cannot set auth tokens associated with accounts of type: %s",
2516 callingUid,
2517 account.type);
2518 throw new SecurityException(msg);
2519 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002520 long identityToken = clearCallingIdentity();
2521 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002522 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002523 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002524 } finally {
2525 restoreCallingIdentity(identityToken);
2526 }
Fred Quintana60307342009-03-24 22:48:12 -07002527 }
2528
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002529 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002530 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002531 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002532 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2533 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002534 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002535 + ", pid " + Binder.getCallingPid());
2536 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002537 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002538 int userId = UserHandle.getCallingUserId();
2539 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002540 String msg = String.format(
2541 "uid %s cannot set secrets for accounts of type: %s",
2542 callingUid,
2543 account.type);
2544 throw new SecurityException(msg);
2545 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002546 long identityToken = clearCallingIdentity();
2547 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002548 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002549 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002550 } finally {
2551 restoreCallingIdentity(identityToken);
2552 }
Fred Quintana60307342009-03-24 22:48:12 -07002553 }
2554
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002555 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2556 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002557 if (account == null) {
2558 return;
2559 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002560 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002561 synchronized (accounts.dbLock) {
2562 synchronized (accounts.cacheLock) {
2563 accounts.accountsDb.beginTransaction();
2564 try {
2565 final long accountId = accounts.accountsDb.findDeAccountId(account);
2566 if (accountId >= 0) {
2567 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2568 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2569 accounts.authTokenCache.remove(account);
2570 accounts.accountTokenCaches.remove(account);
2571 accounts.accountsDb.setTransactionSuccessful();
2572 // If there is an account whose password will be updated and the database
2573 // transactions succeed, then we say that a change has occured. Even if the
2574 // new password is the same as the old and there were no authtokens to
2575 // delete.
2576 isChanged = true;
2577 String action = (password == null || password.length() == 0) ?
2578 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2579 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2580 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2581 callingUid);
2582 }
2583 } finally {
2584 accounts.accountsDb.endTransaction();
2585 if (isChanged) {
2586 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2587 sendNotificationAccountUpdated(account, accounts);
2588 sendAccountsChangedBroadcast(accounts.userId);
2589 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002590 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002591 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002592 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002593 }
2594
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002595 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002596 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002597 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002598 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2599 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002600 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002601 + ", pid " + Binder.getCallingPid());
2602 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002603 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002604 int userId = UserHandle.getCallingUserId();
2605 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002606 String msg = String.format(
2607 "uid %s cannot clear passwords for accounts of type: %s",
2608 callingUid,
2609 account.type);
2610 throw new SecurityException(msg);
2611 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002612 long identityToken = clearCallingIdentity();
2613 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002614 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002615 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002616 } finally {
2617 restoreCallingIdentity(identityToken);
2618 }
Fred Quintana60307342009-03-24 22:48:12 -07002619 }
2620
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002621 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002622 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002623 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002624 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2625 Log.v(TAG, "setUserData: " + account
2626 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002627 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002628 + ", pid " + Binder.getCallingPid());
2629 }
Fred Quintana382601f2010-03-25 12:25:10 -07002630 if (key == null) throw new IllegalArgumentException("key is null");
2631 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002632 int userId = UserHandle.getCallingUserId();
2633 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002634 String msg = String.format(
2635 "uid %s cannot set user data for accounts of type: %s",
2636 callingUid,
2637 account.type);
2638 throw new SecurityException(msg);
2639 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002640 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002641 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002642 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002643 if (!accountExistsCache(accounts, account)) {
2644 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002645 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002646 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002647 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002648 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002649 }
2650 }
2651
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002652 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2653 synchronized (accounts.cacheLock) {
2654 if (accounts.accountCache.containsKey(account.type)) {
2655 for (Account acc : accounts.accountCache.get(account.type)) {
2656 if (acc.name.equals(account.name)) {
2657 return true;
2658 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002659 }
2660 }
2661 }
2662 return false;
2663 }
2664
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002665 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002666 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002667 synchronized (accounts.dbLock) {
2668 accounts.accountsDb.beginTransaction();
2669 try {
2670 long accountId = accounts.accountsDb.findDeAccountId(account);
2671 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002672 return;
2673 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002674 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2675 if (extrasId < 0) {
2676 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2677 if (extrasId < 0) {
2678 return;
2679 }
2680 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2681 return;
2682 }
2683 accounts.accountsDb.setTransactionSuccessful();
2684 } finally {
2685 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002686 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002687 synchronized (accounts.cacheLock) {
2688 writeUserDataIntoCacheLocked(accounts, account, key, value);
2689 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002690 }
2691 }
2692
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002693 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002694 if (result == null) {
2695 Log.e(TAG, "the result is unexpectedly null", new Exception());
2696 }
2697 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2698 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2699 + response);
2700 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002701 try {
2702 response.onResult(result);
2703 } catch (RemoteException e) {
2704 // if the caller is dead then there is no one to care about remote
2705 // exceptions
2706 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2707 Log.v(TAG, "failure while notifying response", e);
2708 }
2709 }
2710 }
2711
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002712 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002713 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2714 final String authTokenType)
2715 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002716 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2717 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002718
Fred Quintanad9640ec2012-05-23 12:37:00 -07002719 final int callingUid = getCallingUid();
2720 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002721 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002722 throw new SecurityException("can only call from system");
2723 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002724 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002725 long identityToken = clearCallingIdentity();
2726 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002727 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002728 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2729 false /* stripAuthTokenFromResult */, null /* accountName */,
2730 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002731 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002732 protected String toDebugString(long now) {
2733 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002734 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002735 + ", authTokenType " + authTokenType;
2736 }
2737
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002738 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002739 public void run() throws RemoteException {
2740 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2741 }
2742
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002743 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002744 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002745 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002746 if (result != null) {
2747 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2748 Bundle bundle = new Bundle();
2749 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2750 super.onResult(bundle);
2751 return;
2752 } else {
2753 super.onResult(result);
2754 }
2755 }
2756 }.bind();
2757 } finally {
2758 restoreCallingIdentity(identityToken);
2759 }
2760 }
2761
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002762 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002763 public void getAuthToken(
2764 IAccountManagerResponse response,
2765 final Account account,
2766 final String authTokenType,
2767 final boolean notifyOnAuthFailure,
2768 final boolean expectActivityLaunch,
2769 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002770 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002771 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2772 Log.v(TAG, "getAuthToken: " + account
2773 + ", response " + response
2774 + ", authTokenType " + authTokenType
2775 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2776 + ", expectActivityLaunch " + expectActivityLaunch
2777 + ", caller's uid " + Binder.getCallingUid()
2778 + ", pid " + Binder.getCallingPid());
2779 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002780 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002781 try {
2782 if (account == null) {
2783 Slog.w(TAG, "getAuthToken called with null account");
2784 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2785 return;
2786 }
2787 if (authTokenType == null) {
2788 Slog.w(TAG, "getAuthToken called with null authTokenType");
2789 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2790 return;
2791 }
2792 } catch (RemoteException e) {
2793 Slog.w(TAG, "Failed to report error back to the client." + e);
2794 return;
2795 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002796 int userId = UserHandle.getCallingUserId();
2797 long ident = Binder.clearCallingIdentity();
2798 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002799 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002800 try {
2801 accounts = getUserAccounts(userId);
2802 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2803 AuthenticatorDescription.newKey(account.type), accounts.userId);
2804 } finally {
2805 Binder.restoreCallingIdentity(ident);
2806 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002807
Costin Manolachea40c6302010-12-13 14:50:45 -08002808 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002809 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002810
2811 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002812 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002813 final boolean permissionGranted =
2814 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002815
Carlos Valdivia91979be2015-05-22 14:11:35 -07002816 // Get the calling package. We will use it for the purpose of caching.
2817 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002818 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002819 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002820 try {
2821 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2822 } finally {
2823 Binder.restoreCallingIdentity(ident);
2824 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002825 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2826 String msg = String.format(
2827 "Uid %s is attempting to illegally masquerade as package %s!",
2828 callerUid,
2829 callerPkg);
2830 throw new SecurityException(msg);
2831 }
2832
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002833 // let authenticator know the identity of the caller
2834 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2835 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002836
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002837 if (notifyOnAuthFailure) {
2838 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002839 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002840
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002841 long identityToken = clearCallingIdentity();
2842 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002843 // Distill the caller's package signatures into a single digest.
2844 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2845
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002846 // if the caller has permission, do the peek. otherwise go the more expensive
2847 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002848 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002849 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002850 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002851 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002852 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2853 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2854 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002855 onResult(response, result);
2856 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002857 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002858 }
2859
Carlos Valdivia91979be2015-05-22 14:11:35 -07002860 if (customTokens) {
2861 /*
2862 * Look up tokens in the new cache only if the loginOptions don't have parameters
2863 * outside of those expected to be injected by the AccountManager, e.g.
2864 * ANDORID_PACKAGE_NAME.
2865 */
2866 String token = readCachedTokenInternal(
2867 accounts,
2868 account,
2869 authTokenType,
2870 callerPkg,
2871 callerPkgSigDigest);
2872 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002873 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2874 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2875 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002876 Bundle result = new Bundle();
2877 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2878 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2879 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2880 onResult(response, result);
2881 return;
2882 }
2883 }
2884
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002885 new Session(
2886 accounts,
2887 response,
2888 account.type,
2889 expectActivityLaunch,
2890 false /* stripAuthTokenFromResult */,
2891 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002892 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002893 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002894 protected String toDebugString(long now) {
2895 if (loginOptions != null) loginOptions.keySet();
2896 return super.toDebugString(now) + ", getAuthToken"
2897 + ", " + account
2898 + ", authTokenType " + authTokenType
2899 + ", loginOptions " + loginOptions
2900 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2901 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002902
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002903 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002904 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002905 // If the caller doesn't have permission then create and return the
2906 // "grant permission" intent instead of the "getAuthToken" intent.
2907 if (!permissionGranted) {
2908 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2909 } else {
2910 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2911 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002912 }
2913
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002914 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002915 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002916 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002917 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002918 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002919 Intent intent = newGrantCredentialsPermissionIntent(
2920 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002921 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002922 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002923 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002924 authTokenType,
2925 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002926 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002927 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002928 onResult(bundle);
2929 return;
2930 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002931 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002932 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002933 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2934 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002935 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002936 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002937 "the type and name should not be empty");
2938 return;
2939 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002940 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002941 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002942 saveAuthTokenToDatabase(
2943 mAccounts,
2944 resultAccount,
2945 authTokenType,
2946 authToken);
2947 }
2948 long expiryMillis = result.getLong(
2949 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2950 if (customTokens
2951 && expiryMillis > System.currentTimeMillis()) {
2952 saveCachedToken(
2953 mAccounts,
2954 account,
2955 callerPkg,
2956 callerPkgSigDigest,
2957 authTokenType,
2958 authToken,
2959 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002960 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002961 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002962
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002963 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002964 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002965 /*
2966 * Make sure that the supplied intent is owned by the authenticator
2967 * giving it to the system. Otherwise a malicious authenticator could
2968 * have users launching arbitrary activities by tricking users to
2969 * interact with malicious notifications.
2970 */
tiansiminga8868bf2017-09-20 13:59:13 +08002971 if (!checkKeyIntent(
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002972 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08002973 intent)) {
2974 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
2975 "invalid intent in bundle returned");
2976 return;
2977 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002978 doNotification(
2979 mAccounts,
2980 account,
2981 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002982 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002983 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002984 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002985 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002986 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002987 }.bind();
2988 } finally {
2989 restoreCallingIdentity(identityToken);
2990 }
Fred Quintana60307342009-03-24 22:48:12 -07002991 }
2992
Carlos Valdivia91979be2015-05-22 14:11:35 -07002993 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2994 MessageDigest digester;
2995 try {
2996 digester = MessageDigest.getInstance("SHA-256");
2997 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2998 callerPkg, PackageManager.GET_SIGNATURES);
2999 for (Signature sig : pkgInfo.signatures) {
3000 digester.update(sig.toByteArray());
3001 }
3002 } catch (NoSuchAlgorithmException x) {
3003 Log.wtf(TAG, "SHA-256 should be available", x);
3004 digester = null;
3005 } catch (NameNotFoundException e) {
3006 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
3007 digester = null;
3008 }
3009 return (digester == null) ? null : digester.digest();
3010 }
3011
Dianne Hackborn41203752012-08-31 14:05:51 -07003012 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003013 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003014 int uid = intent.getIntExtra(
3015 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3016 String authTokenType = intent.getStringExtra(
3017 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07003018 final String titleAndSubtitle =
3019 mContext.getString(R.string.permission_request_notification_with_subtitle,
3020 account.name);
3021 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07003022 String title = titleAndSubtitle;
3023 String subtitle = "";
3024 if (index > 0) {
3025 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04003026 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07003027 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07003028 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003029 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003030 Notification n =
3031 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3032 .setSmallIcon(android.R.drawable.stat_sys_warning)
3033 .setWhen(0)
3034 .setColor(contextForUser.getColor(
3035 com.android.internal.R.color.system_notification_accent_color))
3036 .setContentTitle(title)
3037 .setContentText(subtitle)
3038 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3039 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
3040 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003041 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003042 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003043 }
3044
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003045 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3046 int uid, AccountAuthenticatorResponse response, String authTokenType,
3047 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003048
3049 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003050
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003051 if (startInNewTask) {
3052 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3053 // Since it was set in Eclair+ we can't change it without breaking apps using
3054 // the intent from a non-Activity context. This is the default behavior.
3055 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3056 }
Chris Wren717a8812017-03-31 15:34:39 -04003057 intent.addCategory(getCredentialPermissionNotificationId(account,
3058 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003059 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003060 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3061 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003062 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003063
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003064 return intent;
3065 }
3066
Chris Wren717a8812017-03-31 15:34:39 -04003067 private NotificationId getCredentialPermissionNotificationId(Account account,
3068 String authTokenType, int uid) {
3069 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003070 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003071 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003072 final Pair<Pair<Account, String>, Integer> key =
3073 new Pair<Pair<Account, String>, Integer>(
3074 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04003075 nId = accounts.credentialsPermissionNotificationIds.get(key);
3076 if (nId == null) {
3077 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3078 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
3079 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3080 nId = new NotificationId(tag, id);
3081 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003082 }
3083 }
Chris Wren717a8812017-03-31 15:34:39 -04003084 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003085 }
3086
Chris Wren717a8812017-03-31 15:34:39 -04003087 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3088 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08003089 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04003090 nId = accounts.signinRequiredNotificationIds.get(account);
3091 if (nId == null) {
3092 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3093 + ":" + account.hashCode();
3094 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3095 nId = new NotificationId(tag, id);
3096 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003097 }
3098 }
Chris Wren717a8812017-03-31 15:34:39 -04003099 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003100 }
3101
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003102 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07003103 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003104 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003105 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003106 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003107 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3108 Log.v(TAG, "addAccount: accountType " + accountType
3109 + ", response " + response
3110 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003111 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003112 + ", expectActivityLaunch " + expectActivityLaunch
3113 + ", caller's uid " + Binder.getCallingUid()
3114 + ", pid " + Binder.getCallingPid());
3115 }
Fred Quintana382601f2010-03-25 12:25:10 -07003116 if (response == null) throw new IllegalArgumentException("response is null");
3117 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003118
Amith Yamasani71e6c692013-03-24 17:39:28 -07003119 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003120 final int uid = Binder.getCallingUid();
3121 final int userId = UserHandle.getUserId(uid);
3122 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003123 try {
3124 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3125 "User is not allowed to add an account!");
3126 } catch (RemoteException re) {
3127 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003128 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003129 return;
3130 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003131 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003132 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003133 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3134 "User cannot modify accounts of this type (policy).");
3135 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003136 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003137 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3138 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003139 return;
3140 }
3141
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003142 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003143 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3144 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3145 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3146
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003147 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003148 long identityToken = clearCallingIdentity();
3149 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003150 UserAccounts accounts = getUserAccounts(usrId);
3151 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003152 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3153 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003154 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003155 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003156 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003157 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003158 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003159 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003160 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003161 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003162
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003163 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003164 protected String toDebugString(long now) {
3165 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003166 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003167 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003168 }
3169 }.bind();
3170 } finally {
3171 restoreCallingIdentity(identityToken);
3172 }
Fred Quintana60307342009-03-24 22:48:12 -07003173 }
3174
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003175 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003176 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3177 final String authTokenType, final String[] requiredFeatures,
3178 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003179 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003180 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003181 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3182 Log.v(TAG, "addAccount: accountType " + accountType
3183 + ", response " + response
3184 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003185 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003186 + ", expectActivityLaunch " + expectActivityLaunch
3187 + ", caller's uid " + Binder.getCallingUid()
3188 + ", pid " + Binder.getCallingPid()
3189 + ", for user id " + userId);
3190 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003191 Preconditions.checkArgument(response != null, "response cannot be null");
3192 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003193 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003194 if (isCrossUser(callingUid, userId)) {
3195 throw new SecurityException(
3196 String.format(
3197 "User %s trying to add account for %s" ,
3198 UserHandle.getCallingUserId(),
3199 userId));
3200 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003201
3202 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003203 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003204 try {
3205 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3206 "User is not allowed to add an account!");
3207 } catch (RemoteException re) {
3208 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003209 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003210 return;
3211 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003212 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003213 try {
3214 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3215 "User cannot modify accounts of this type (policy).");
3216 } catch (RemoteException re) {
3217 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003218 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3219 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003220 return;
3221 }
3222
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003223 final int pid = Binder.getCallingPid();
3224 final int uid = Binder.getCallingUid();
3225 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3226 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3227 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3228
3229 long identityToken = clearCallingIdentity();
3230 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003231 UserAccounts accounts = getUserAccounts(userId);
3232 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003233 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3234 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003235 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003236 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003237 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003238 @Override
3239 public void run() throws RemoteException {
3240 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3241 options);
3242 }
3243
3244 @Override
3245 protected String toDebugString(long now) {
3246 return super.toDebugString(now) + ", addAccount"
3247 + ", accountType " + accountType
3248 + ", requiredFeatures "
3249 + (requiredFeatures != null
3250 ? TextUtils.join(",", requiredFeatures)
3251 : null);
3252 }
3253 }.bind();
3254 } finally {
3255 restoreCallingIdentity(identityToken);
3256 }
3257 }
3258
Sandra Kwan78812282015-11-04 11:19:47 -08003259 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003260 public void startAddAccountSession(
3261 final IAccountManagerResponse response,
3262 final String accountType,
3263 final String authTokenType,
3264 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003265 final boolean expectActivityLaunch,
3266 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003267 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003268 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3269 Log.v(TAG,
3270 "startAddAccountSession: accountType " + accountType
3271 + ", response " + response
3272 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003273 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003274 + ", expectActivityLaunch " + expectActivityLaunch
3275 + ", caller's uid " + Binder.getCallingUid()
3276 + ", pid " + Binder.getCallingPid());
3277 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003278 Preconditions.checkArgument(response != null, "response cannot be null");
3279 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003280
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003281 final int uid = Binder.getCallingUid();
3282 final int userId = UserHandle.getUserId(uid);
3283 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003284 try {
3285 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3286 "User is not allowed to add an account!");
3287 } catch (RemoteException re) {
3288 }
3289 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3290 return;
3291 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003292 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003293 try {
3294 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3295 "User cannot modify accounts of this type (policy).");
3296 } catch (RemoteException re) {
3297 }
3298 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3299 userId);
3300 return;
3301 }
Sandra Kwan78812282015-11-04 11:19:47 -08003302 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003303 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3304 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3305 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3306
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003307 // Check to see if the Password should be included to the caller.
3308 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3309 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003310 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003311
Sandra Kwan78812282015-11-04 11:19:47 -08003312 long identityToken = clearCallingIdentity();
3313 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003314 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003315 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3316 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003317 new StartAccountSession(
3318 accounts,
3319 response,
3320 accountType,
3321 expectActivityLaunch,
3322 null /* accountName */,
3323 false /* authDetailsRequired */,
3324 true /* updateLastAuthenticationTime */,
3325 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003326 @Override
3327 public void run() throws RemoteException {
3328 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3329 requiredFeatures, options);
3330 }
3331
3332 @Override
3333 protected String toDebugString(long now) {
3334 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3335 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3336 + accountType + ", requiredFeatures "
3337 + (requiredFeatures != null ? requiredFeaturesStr : null);
3338 }
3339 }.bind();
3340 } finally {
3341 restoreCallingIdentity(identityToken);
3342 }
3343 }
3344
3345 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3346 private abstract class StartAccountSession extends Session {
3347
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003348 private final boolean mIsPasswordForwardingAllowed;
3349
3350 public StartAccountSession(
3351 UserAccounts accounts,
3352 IAccountManagerResponse response,
3353 String accountType,
3354 boolean expectActivityLaunch,
3355 String accountName,
3356 boolean authDetailsRequired,
3357 boolean updateLastAuthenticationTime,
3358 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003359 super(accounts, response, accountType, expectActivityLaunch,
3360 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3361 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003362 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003363 }
3364
3365 @Override
3366 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003367 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003368 mNumResults++;
3369 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003370 if (result != null
3371 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08003372 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003373 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08003374 intent)) {
3375 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3376 "invalid intent in bundle returned");
3377 return;
3378 }
Sandra Kwan78812282015-11-04 11:19:47 -08003379 }
Sandra Kwan78812282015-11-04 11:19:47 -08003380 IAccountManagerResponse response;
3381 if (mExpectActivityLaunch && result != null
3382 && result.containsKey(AccountManager.KEY_INTENT)) {
3383 response = mResponse;
3384 } else {
3385 response = getResponseAndClose();
3386 }
3387 if (response == null) {
3388 return;
3389 }
3390 if (result == null) {
3391 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3392 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3393 + response);
3394 }
3395 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3396 "null bundle returned");
3397 return;
3398 }
3399
3400 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3401 // All AccountManager error codes are greater
3402 // than 0
3403 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3404 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3405 return;
3406 }
3407
Hongming Jin368aa192016-07-29 14:29:54 -07003408 // Omit passwords if the caller isn't permitted to see them.
3409 if (!mIsPasswordForwardingAllowed) {
3410 result.remove(AccountManager.KEY_PASSWORD);
3411 }
3412
Sandra Kwan78812282015-11-04 11:19:47 -08003413 // Strip auth token from result.
3414 result.remove(AccountManager.KEY_AUTHTOKEN);
3415
3416 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3417 Log.v(TAG,
3418 getClass().getSimpleName() + " calling onResult() on response " + response);
3419 }
3420
3421 // Get the session bundle created by authenticator. The
3422 // bundle contains data necessary for finishing the session
3423 // later. The session bundle will be encrypted here and
3424 // decrypted later when trying to finish the session.
3425 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3426 if (sessionBundle != null) {
3427 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3428 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003429 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003430 Log.w(TAG, "Account type in session bundle doesn't match request.");
3431 }
3432 // Add accountType info to session bundle. This will
3433 // override any value set by authenticator.
3434 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3435
3436 // Encrypt session bundle before returning to caller.
3437 try {
3438 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3439 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3440 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3441 } catch (GeneralSecurityException e) {
3442 if (Log.isLoggable(TAG, Log.DEBUG)) {
3443 Log.v(TAG, "Failed to encrypt session bundle!", e);
3444 }
3445 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3446 "failed to encrypt session bundle");
3447 return;
3448 }
3449 }
3450
3451 sendResponse(response, result);
3452 }
3453 }
3454
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003455 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003456 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003457 @NonNull Bundle sessionBundle,
3458 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003459 Bundle appInfo,
3460 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003461 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003462 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003463 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3464 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003465 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003466 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003467 + ", caller's uid " + callingUid
3468 + ", caller's user id " + UserHandle.getCallingUserId()
3469 + ", pid " + Binder.getCallingPid()
3470 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003471 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003472 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003473 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3474 // Account type is added to it before encryption.
3475 if (sessionBundle == null || sessionBundle.size() == 0) {
3476 throw new IllegalArgumentException("sessionBundle is empty");
3477 }
3478
Dmitry Dementyev52745472016-12-02 10:27:45 -08003479 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003480 if (isCrossUser(callingUid, userId)) {
3481 throw new SecurityException(
3482 String.format(
3483 "User %s trying to finish session for %s without cross user permission",
3484 UserHandle.getCallingUserId(),
3485 userId));
3486 }
3487
Sandra Kwan0b84b452016-01-20 15:25:42 -08003488 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003489 sendErrorResponse(response,
3490 AccountManager.ERROR_CODE_USER_RESTRICTED,
3491 "User is not allowed to add an account!");
3492 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3493 return;
3494 }
3495
3496 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003497 final Bundle decryptedBundle;
3498 final String accountType;
3499 // First decrypt session bundle to get account type for checking permission.
3500 try {
3501 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3502 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3503 if (decryptedBundle == null) {
3504 sendErrorResponse(
3505 response,
3506 AccountManager.ERROR_CODE_BAD_REQUEST,
3507 "failed to decrypt session bundle");
3508 return;
3509 }
3510 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3511 // Account type cannot be null. This should not happen if session bundle was created
3512 // properly by #StartAccountSession.
3513 if (TextUtils.isEmpty(accountType)) {
3514 sendErrorResponse(
3515 response,
3516 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3517 "accountType is empty");
3518 return;
3519 }
3520
3521 // If by any chances, decryptedBundle contains colliding keys with
3522 // system info
3523 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3524 // update credentials flow, we should replace with the new values of the current call.
3525 if (appInfo != null) {
3526 decryptedBundle.putAll(appInfo);
3527 }
3528
3529 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003530 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003531 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3532 } catch (GeneralSecurityException e) {
3533 if (Log.isLoggable(TAG, Log.DEBUG)) {
3534 Log.v(TAG, "Failed to decrypt session bundle!", e);
3535 }
3536 sendErrorResponse(
3537 response,
3538 AccountManager.ERROR_CODE_BAD_REQUEST,
3539 "failed to decrypt session bundle");
3540 return;
3541 }
3542
Sandra Kwan0b84b452016-01-20 15:25:42 -08003543 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003544 sendErrorResponse(
3545 response,
3546 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3547 "User cannot modify accounts of this type (policy).");
3548 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3549 userId);
3550 return;
3551 }
3552
3553 long identityToken = clearCallingIdentity();
3554 try {
3555 UserAccounts accounts = getUserAccounts(userId);
3556 logRecordWithUid(
3557 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003558 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3559 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003560 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003561 new Session(
3562 accounts,
3563 response,
3564 accountType,
3565 expectActivityLaunch,
3566 true /* stripAuthTokenFromResult */,
3567 null /* accountName */,
3568 false /* authDetailsRequired */,
3569 true /* updateLastAuthenticationTime */) {
3570 @Override
3571 public void run() throws RemoteException {
3572 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3573 }
3574
3575 @Override
3576 protected String toDebugString(long now) {
3577 return super.toDebugString(now)
3578 + ", finishSession"
3579 + ", accountType " + accountType;
3580 }
3581 }.bind();
3582 } finally {
3583 restoreCallingIdentity(identityToken);
3584 }
3585 }
3586
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003587 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003588 final DevicePolicyManagerInternal dpmi =
3589 LocalServices.getService(DevicePolicyManagerInternal.class);
3590 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003591 if (dpmi == null) {
3592 intent = getDefaultCantAddAccountIntent(errorCode);
3593 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003594 intent = dpmi.createUserRestrictionSupportIntent(userId,
3595 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3596 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3597 intent = dpmi.createShowAdminSupportIntent(userId, false);
3598 }
3599 if (intent == null) {
3600 intent = getDefaultCantAddAccountIntent(errorCode);
3601 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003602 long identityToken = clearCallingIdentity();
3603 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003604 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003605 } finally {
3606 restoreCallingIdentity(identityToken);
3607 }
3608 }
3609
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003610 /**
3611 * Called when we don't know precisely who is preventing us from adding an account.
3612 */
3613 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3614 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3615 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3616 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3617 return cantAddAccount;
3618 }
3619
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003620 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003621 public void confirmCredentialsAsUser(
3622 IAccountManagerResponse response,
3623 final Account account,
3624 final Bundle options,
3625 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003626 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003627 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003628 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003629 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3630 Log.v(TAG, "confirmCredentials: " + account
3631 + ", response " + response
3632 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003633 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003634 + ", pid " + Binder.getCallingPid());
3635 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003636 // Only allow the system process to read accounts of other users
3637 if (isCrossUser(callingUid, userId)) {
3638 throw new SecurityException(
3639 String.format(
3640 "User %s trying to confirm account credentials for %s" ,
3641 UserHandle.getCallingUserId(),
3642 userId));
3643 }
Fred Quintana382601f2010-03-25 12:25:10 -07003644 if (response == null) throw new IllegalArgumentException("response is null");
3645 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003646 long identityToken = clearCallingIdentity();
3647 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003648 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003649 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003650 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003651 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003652 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003653 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003654 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003655 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003656 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003657 protected String toDebugString(long now) {
3658 return super.toDebugString(now) + ", confirmCredentials"
3659 + ", " + account;
3660 }
3661 }.bind();
3662 } finally {
3663 restoreCallingIdentity(identityToken);
3664 }
Fred Quintana60307342009-03-24 22:48:12 -07003665 }
3666
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003667 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003668 public void updateCredentials(IAccountManagerResponse response, final Account account,
3669 final String authTokenType, final boolean expectActivityLaunch,
3670 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003671 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003672 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3673 Log.v(TAG, "updateCredentials: " + account
3674 + ", response " + response
3675 + ", authTokenType " + authTokenType
3676 + ", expectActivityLaunch " + expectActivityLaunch
3677 + ", caller's uid " + Binder.getCallingUid()
3678 + ", pid " + Binder.getCallingPid());
3679 }
Fred Quintana382601f2010-03-25 12:25:10 -07003680 if (response == null) throw new IllegalArgumentException("response is null");
3681 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003682 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003683 long identityToken = clearCallingIdentity();
3684 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003685 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003686 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003687 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003688 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003689 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003690 public void run() throws RemoteException {
3691 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3692 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003693 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003694 protected String toDebugString(long now) {
3695 if (loginOptions != null) loginOptions.keySet();
3696 return super.toDebugString(now) + ", updateCredentials"
3697 + ", " + account
3698 + ", authTokenType " + authTokenType
3699 + ", loginOptions " + loginOptions;
3700 }
3701 }.bind();
3702 } finally {
3703 restoreCallingIdentity(identityToken);
3704 }
Fred Quintana60307342009-03-24 22:48:12 -07003705 }
3706
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003707 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003708 public void startUpdateCredentialsSession(
3709 IAccountManagerResponse response,
3710 final Account account,
3711 final String authTokenType,
3712 final boolean expectActivityLaunch,
3713 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003714 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003715 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3716 Log.v(TAG,
3717 "startUpdateCredentialsSession: " + account + ", response " + response
3718 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3719 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3720 + ", pid " + Binder.getCallingPid());
3721 }
3722 if (response == null) {
3723 throw new IllegalArgumentException("response is null");
3724 }
3725 if (account == null) {
3726 throw new IllegalArgumentException("account is null");
3727 }
Sandra Kwana578d112015-12-16 16:01:43 -08003728
3729 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003730 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003731
3732 // Check to see if the Password should be included to the caller.
3733 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3734 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003735 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003736
Sandra Kwane68c37e2015-11-12 17:11:49 -08003737 long identityToken = clearCallingIdentity();
3738 try {
3739 UserAccounts accounts = getUserAccounts(userId);
3740 new StartAccountSession(
3741 accounts,
3742 response,
3743 account.type,
3744 expectActivityLaunch,
3745 account.name,
3746 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003747 true /* updateLastCredentialTime */,
3748 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003749 @Override
3750 public void run() throws RemoteException {
3751 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3752 loginOptions);
3753 }
3754
3755 @Override
3756 protected String toDebugString(long now) {
3757 if (loginOptions != null)
3758 loginOptions.keySet();
3759 return super.toDebugString(now)
3760 + ", startUpdateCredentialsSession"
3761 + ", " + account
3762 + ", authTokenType " + authTokenType
3763 + ", loginOptions " + loginOptions;
3764 }
3765 }.bind();
3766 } finally {
3767 restoreCallingIdentity(identityToken);
3768 }
3769 }
3770
3771 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003772 public void isCredentialsUpdateSuggested(
3773 IAccountManagerResponse response,
3774 final Account account,
3775 final String statusToken) {
3776 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3777 Log.v(TAG,
3778 "isCredentialsUpdateSuggested: " + account + ", response " + response
3779 + ", caller's uid " + Binder.getCallingUid()
3780 + ", pid " + Binder.getCallingPid());
3781 }
3782 if (response == null) {
3783 throw new IllegalArgumentException("response is null");
3784 }
3785 if (account == null) {
3786 throw new IllegalArgumentException("account is null");
3787 }
3788 if (TextUtils.isEmpty(statusToken)) {
3789 throw new IllegalArgumentException("status token is empty");
3790 }
3791
Sandra Kwan390c9d22016-01-12 14:13:37 -08003792 int usrId = UserHandle.getCallingUserId();
3793 long identityToken = clearCallingIdentity();
3794 try {
3795 UserAccounts accounts = getUserAccounts(usrId);
3796 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3797 false /* stripAuthTokenFromResult */, account.name,
3798 false /* authDetailsRequired */) {
3799 @Override
3800 protected String toDebugString(long now) {
3801 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3802 + ", " + account;
3803 }
3804
3805 @Override
3806 public void run() throws RemoteException {
3807 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3808 }
3809
3810 @Override
3811 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003812 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003813 IAccountManagerResponse response = getResponseAndClose();
3814 if (response == null) {
3815 return;
3816 }
3817
3818 if (result == null) {
3819 sendErrorResponse(
3820 response,
3821 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3822 "null bundle");
3823 return;
3824 }
3825
3826 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3827 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3828 + response);
3829 }
3830 // Check to see if an error occurred. We know if an error occurred because all
3831 // error codes are greater than 0.
3832 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3833 sendErrorResponse(response,
3834 result.getInt(AccountManager.KEY_ERROR_CODE),
3835 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3836 return;
3837 }
3838 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3839 sendErrorResponse(
3840 response,
3841 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3842 "no result in response");
3843 return;
3844 }
3845 final Bundle newResult = new Bundle();
3846 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3847 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3848 sendResponse(response, newResult);
3849 }
3850 }.bind();
3851 } finally {
3852 restoreCallingIdentity(identityToken);
3853 }
3854 }
3855
3856 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003857 public void editProperties(IAccountManagerResponse response, final String accountType,
3858 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003859 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003860 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3861 Log.v(TAG, "editProperties: accountType " + accountType
3862 + ", response " + response
3863 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003864 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003865 + ", pid " + Binder.getCallingPid());
3866 }
Fred Quintana382601f2010-03-25 12:25:10 -07003867 if (response == null) throw new IllegalArgumentException("response is null");
3868 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003869 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003870 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3871 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003872 String msg = String.format(
3873 "uid %s cannot edit authenticator properites for account type: %s",
3874 callingUid,
3875 accountType);
3876 throw new SecurityException(msg);
3877 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003878 long identityToken = clearCallingIdentity();
3879 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003880 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003881 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003882 true /* stripAuthTokenFromResult */, null /* accountName */,
3883 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003884 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003885 public void run() throws RemoteException {
3886 mAuthenticator.editProperties(this, mAccountType);
3887 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003888 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003889 protected String toDebugString(long now) {
3890 return super.toDebugString(now) + ", editProperties"
3891 + ", accountType " + accountType;
3892 }
3893 }.bind();
3894 } finally {
3895 restoreCallingIdentity(identityToken);
3896 }
Fred Quintana60307342009-03-24 22:48:12 -07003897 }
3898
Amith Yamasani12747872015-12-07 14:19:49 -08003899 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003900 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3901 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003902 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003903 throw new SecurityException("Can be called only by system UID");
3904 }
3905 Preconditions.checkNotNull(account, "account cannot be null");
3906 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3907 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3908
3909 final int userId = userHandle.getIdentifier();
3910
3911 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3912
3913 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003914 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003915 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003916 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003917 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003918 return false;
3919 }
3920 }
3921
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003922 // Returns package with oldest target SDK for given UID.
3923 private String getPackageNameForUid(int uid) {
3924 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3925 if (ArrayUtils.isEmpty(packageNames)) {
3926 return null;
3927 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003928 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003929 if (packageNames.length == 1) {
3930 return packageName;
3931 }
3932 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003933 int oldestVersion = Integer.MAX_VALUE;
3934 for (String name : packageNames) {
3935 try {
3936 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3937 if (applicationInfo != null) {
3938 int version = applicationInfo.targetSdkVersion;
3939 if (version < oldestVersion) {
3940 oldestVersion = version;
3941 packageName = name;
3942 }
3943 }
3944 } catch (NameNotFoundException e) {
3945 // skip
3946 }
3947 }
3948 return packageName;
3949 }
3950
Svet Ganovf6d424f12016-09-20 20:18:53 -07003951 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3952 int uid) {
3953 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003954 packageName = getPackageNameForUid(uid);
3955 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003956 return false;
3957 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003958 }
3959
3960 // Use null token which means any token. Having a token means the package
3961 // is trusted by the authenticator, hence it is fine to access the account.
3962 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3963 return true;
3964 }
3965 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003966 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003967
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003968 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003969 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003970 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003971 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003972 }
3973
3974 @Override
3975 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3976 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003977 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003978 throw new SecurityException("Can be called only by system UID");
3979 }
3980
3981 Preconditions.checkNotNull(account, "account cannot be null");
3982 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3983 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3984
3985 final int userId = userHandle.getIdentifier();
3986
3987 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3988
3989 final int uid;
3990 try {
3991 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3992 } catch (NameNotFoundException e) {
3993 Slog.e(TAG, "Unknown package " + packageName);
3994 return null;
3995 }
3996
3997 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3998
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003999 final long identity = Binder.clearCallingIdentity();
4000 try {
4001 return PendingIntent.getActivityAsUser(
4002 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
4003 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
4004 null, new UserHandle(userId)).getIntentSender();
4005 } finally {
4006 Binder.restoreCallingIdentity(identity);
4007 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004008 }
4009
4010 private Intent newRequestAccountAccessIntent(Account account, String packageName,
4011 int uid, RemoteCallback callback) {
4012 return newGrantCredentialsPermissionIntent(account, packageName, uid,
4013 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
4014 @Override
4015 public void onResult(Bundle value) throws RemoteException {
4016 handleAuthenticatorResponse(true);
4017 }
4018
4019 @Override
4020 public void onRequestContinued() {
4021 /* ignore */
4022 }
4023
4024 @Override
4025 public void onError(int errorCode, String errorMessage) throws RemoteException {
4026 handleAuthenticatorResponse(false);
4027 }
4028
4029 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4030 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07004031 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004032 UserHandle.getUserHandleForUid(uid));
4033 if (callback != null) {
4034 Bundle result = new Bundle();
4035 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4036 callback.sendResult(result);
4037 }
4038 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07004039 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004040 }
4041
4042 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08004043 public boolean someUserHasAccount(@NonNull final Account account) {
4044 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4045 throw new SecurityException("Only system can check for accounts across users");
4046 }
4047 final long token = Binder.clearCallingIdentity();
4048 try {
4049 AccountAndUser[] allAccounts = getAllAccounts();
4050 for (int i = allAccounts.length - 1; i >= 0; i--) {
4051 if (allAccounts[i].account.equals(account)) {
4052 return true;
4053 }
4054 }
4055 return false;
4056 } finally {
4057 Binder.restoreCallingIdentity(token);
4058 }
4059 }
4060
Fred Quintana33269202009-04-20 16:05:10 -07004061 private class GetAccountsByTypeAndFeatureSession extends Session {
4062 private final String[] mFeatures;
4063 private volatile Account[] mAccountsOfType = null;
4064 private volatile ArrayList<Account> mAccountsWithFeatures = null;
4065 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004066 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004067 private final String mPackageName;
sunjianf29d5492017-05-11 15:42:31 -07004068 private final boolean mIncludeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004069
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004070 public GetAccountsByTypeAndFeatureSession(
4071 UserAccounts accounts,
4072 IAccountManagerResponse response,
4073 String type,
4074 String[] features,
4075 int callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004076 String packageName,
4077 boolean includeManagedNotVisible) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004078 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004079 true /* stripAuthTokenFromResult */, null /* accountName */,
4080 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004081 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07004082 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004083 mPackageName = packageName;
sunjianf29d5492017-05-11 15:42:31 -07004084 mIncludeManagedNotVisible = includeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004085 }
4086
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004087 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004088 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004089 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
sunjianf29d5492017-05-11 15:42:31 -07004090 mCallingUid, mPackageName, mIncludeManagedNotVisible);
Fred Quintana33269202009-04-20 16:05:10 -07004091 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07004092 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07004093 mCurrentAccount = 0;
4094
4095 checkAccount();
4096 }
4097
4098 public void checkAccount() {
4099 if (mCurrentAccount >= mAccountsOfType.length) {
4100 sendResult();
4101 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07004102 }
Fred Quintana33269202009-04-20 16:05:10 -07004103
Fred Quintana29e94b82010-03-10 12:11:51 -08004104 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4105 if (accountAuthenticator == null) {
4106 // It is possible that the authenticator has died, which is indicated by
4107 // mAuthenticator being set to null. If this happens then just abort.
4108 // There is no need to send back a result or error in this case since
4109 // that already happened when mAuthenticator was cleared.
4110 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4111 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4112 + " connected to the authenticator, " + toDebugString());
4113 }
4114 return;
4115 }
Fred Quintana33269202009-04-20 16:05:10 -07004116 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004117 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004118 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004119 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004120 }
4121 }
4122
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004123 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004124 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004125 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004126 mNumResults++;
4127 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004128 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004129 return;
4130 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004131 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004132 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4133 }
4134 mCurrentAccount++;
4135 checkAccount();
4136 }
4137
4138 public void sendResult() {
4139 IAccountManagerResponse response = getResponseAndClose();
4140 if (response != null) {
4141 try {
4142 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4143 for (int i = 0; i < accounts.length; i++) {
4144 accounts[i] = mAccountsWithFeatures.get(i);
4145 }
Fred Quintana56285a62010-12-02 14:20:51 -08004146 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4147 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4148 + response);
4149 }
Fred Quintana33269202009-04-20 16:05:10 -07004150 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004151 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004152 response.onResult(result);
4153 } catch (RemoteException e) {
4154 // if the caller is dead then there is no one to care about remote exceptions
4155 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4156 Log.v(TAG, "failure while notifying response", e);
4157 }
4158 }
4159 }
4160 }
4161
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004162 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004163 protected String toDebugString(long now) {
4164 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4165 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4166 }
4167 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004168
Amith Yamasani04e0d262012-02-14 11:50:53 -08004169 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004170 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004171 * @hide
4172 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004173 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004174 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004175 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004176 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004177 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4178 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004179 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004180 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004181 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004182 long identityToken = clearCallingIdentity();
4183 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004184 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004185 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004186 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004187 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004188 opPackageName,
4189 visibleAccountTypes,
4190 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004191 } finally {
4192 restoreCallingIdentity(identityToken);
4193 }
4194 }
4195
Amith Yamasanif29f2362012-04-05 18:29:52 -07004196 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004197 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004198 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004199 * @hide
4200 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004201 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004202 public AccountAndUser[] getRunningAccounts() {
4203 final int[] runningUserIds;
4204 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004205 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004206 } catch (RemoteException e) {
4207 // Running in system_server; should never happen
4208 throw new RuntimeException(e);
4209 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004210 return getAccounts(runningUserIds);
4211 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004212
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004213 /**
4214 * Returns accounts for all users, ignores visibility values.
4215 *
4216 * @hide
4217 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004218 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004219 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004220 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004221 final int[] userIds = new int[users.size()];
4222 for (int i = 0; i < userIds.length; i++) {
4223 userIds[i] = users.get(i).id;
4224 }
4225 return getAccounts(userIds);
4226 }
4227
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004228 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004229 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004230 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004231 for (int userId : userIds) {
4232 UserAccounts userAccounts = getUserAccounts(userId);
4233 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004234 Account[] accounts = getAccountsFromCache(
4235 userAccounts,
4236 null /* type */,
4237 Binder.getCallingUid(),
4238 null /* packageName */,
4239 false /* include managed not visible*/);
4240 for (Account account : accounts) {
4241 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004242 }
4243 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004244
4245 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4246 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004247 }
4248
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004249 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004250 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004251 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004252 int callingUid = Binder.getCallingUid();
4253 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004254 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004255 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004256 }
4257
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004258 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004259 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004260 String type,
4261 int userId,
4262 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004263 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004264 String opPackageName,
4265 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004266 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004267 // Only allow the system process to read accounts of other users
4268 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004269 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004270 && mContext.checkCallingOrSelfPermission(
4271 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4272 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004273 throw new SecurityException("User " + UserHandle.getCallingUserId()
4274 + " trying to get account for " + userId);
4275 }
4276
Fred Quintana56285a62010-12-02 14:20:51 -08004277 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4278 Log.v(TAG, "getAccounts: accountType " + type
4279 + ", caller's uid " + Binder.getCallingUid()
4280 + ", pid " + Binder.getCallingPid());
4281 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004282
4283 // If the original calling app was using account choosing activity
4284 // provided by the framework or authenticator we'll passing in
4285 // the original caller's uid here, which is what should be used for filtering.
4286 List<String> managedTypes =
4287 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4288 if (packageUid != -1 &&
4289 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4290 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004291 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004292 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004293 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004294 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4295 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004296 if (visibleAccountTypes.isEmpty()
4297 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004298 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004299 } else if (visibleAccountTypes.contains(type)) {
4300 // Prune the list down to just the requested type.
4301 visibleAccountTypes = new ArrayList<>();
4302 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004303 } // else aggregate all the visible accounts (it won't matter if the
4304 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004305
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004306 long identityToken = clearCallingIdentity();
4307 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004308 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004309 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004310 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004311 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004312 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004313 visibleAccountTypes,
4314 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004315 } finally {
4316 restoreCallingIdentity(identityToken);
4317 }
4318 }
4319
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004320 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004321 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004322 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004323 int callingUid,
4324 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004325 List<String> visibleAccountTypes,
4326 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004327 ArrayList<Account> visibleAccounts = new ArrayList<>();
4328 for (String visibleType : visibleAccountTypes) {
4329 Account[] accountsForType = getAccountsFromCache(
4330 userAccounts, visibleType, callingUid, callingPackage,
4331 includeUserManagedNotVisible);
4332 if (accountsForType != null) {
4333 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004334 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004335 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004336 Account[] result = new Account[visibleAccounts.size()];
4337 for (int i = 0; i < visibleAccounts.size(); i++) {
4338 result[i] = visibleAccounts.get(i);
4339 }
4340 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004341 }
4342
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004343 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004344 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4345 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004346 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004347 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004348 for (Account account : accounts) {
4349 addSharedAccountAsUser(account, userId);
4350 }
4351 }
4352
4353 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004354 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004355 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004356 accounts.accountsDb.deleteSharedAccount(account);
4357 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004358 if (accountId < 0) {
4359 Log.w(TAG, "insertAccountIntoDatabase: " + account
4360 + ", skipping the DB insert failed");
4361 return false;
4362 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004363 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4364 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004365 return true;
4366 }
4367
4368 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004369 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4370 userId = handleIncomingUser(userId);
4371 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004372 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4373 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004374 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004375 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004376 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004377 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004378 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004379 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004380 }
4381 return r > 0;
4382 }
4383
4384 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004385 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004386 return removeSharedAccountAsUser(account, userId, getCallingUid());
4387 }
4388
4389 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004390 userId = handleIncomingUser(userId);
4391 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004392 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4393 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004394 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004395 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004396 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004397 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004398 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004399 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004400 }
4401
4402 @Override
4403 public Account[] getSharedAccountsAsUser(int userId) {
4404 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004405 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004406 synchronized (accounts.dbLock) {
4407 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4408 Account[] accountArray = new Account[accountList.size()];
4409 accountList.toArray(accountArray);
4410 return accountArray;
4411 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004412 }
4413
4414 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004415 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004416 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004417 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004418 }
4419
Amith Yamasani27db4682013-03-30 17:07:47 -07004420 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004421 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004422 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004423 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004424 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004425 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004426 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4427 + callingUid + " with uid=" + uid);
4428 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004429 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004430 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004431 }
4432
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004433 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004434 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004435 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4436 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004437 int callingUid = Binder.getCallingUid();
4438 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004439 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004440 int packageUid = -1;
4441 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004442 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4443 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004444 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004445 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004446 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004447 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004448 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4449 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004450 }
sunjiand62dc392017-06-01 12:05:59 -07004451 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4452 return getAccountsAsUserForPackage(type, userId,
4453 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4454 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004455 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004456 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004457 }
4458
sunjianf29d5492017-05-11 15:42:31 -07004459 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4460 if (accounts.length < 1) return false;
4461 if (accounts.length > 1) return true;
4462 Account account = accounts[0];
4463 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4464 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4465 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4466 return false;
4467 }
4468
4469 private void startChooseAccountActivityWithAccounts(
sunjianbdabd402017-06-06 17:54:07 -07004470 IAccountManagerResponse response, Account[] accounts, String callingPackage) {
sunjianf29d5492017-05-11 15:42:31 -07004471 Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4472 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4473 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4474 new AccountManagerResponse(response));
sunjianbdabd402017-06-06 17:54:07 -07004475 intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004476
4477 mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4478 }
4479
4480 private void handleGetAccountsResult(
4481 IAccountManagerResponse response,
4482 Account[] accounts,
4483 String callingPackage) {
4484
4485 if (needToStartChooseAccountActivity(accounts, callingPackage)) {
sunjianbdabd402017-06-06 17:54:07 -07004486 startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004487 return;
4488 }
4489 if (accounts.length == 1) {
4490 Bundle bundle = new Bundle();
4491 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4492 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4493 onResult(response, bundle);
4494 return;
4495 }
4496 // No qualified account exists, return an empty Bundle.
4497 onResult(response, new Bundle());
4498 }
4499
4500 @Override
4501 public void getAccountByTypeAndFeatures(
4502 IAccountManagerResponse response,
4503 String accountType,
4504 String[] features,
4505 String opPackageName) {
4506
4507 int callingUid = Binder.getCallingUid();
4508 mAppOpsManager.checkPackage(callingUid, opPackageName);
4509 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4510 Log.v(TAG, "getAccount: accountType " + accountType
4511 + ", response " + response
4512 + ", features " + Arrays.toString(features)
4513 + ", caller's uid " + callingUid
4514 + ", pid " + Binder.getCallingPid());
4515 }
4516 if (response == null) throw new IllegalArgumentException("response is null");
4517 if (accountType == null) throw new IllegalArgumentException("accountType is null");
4518
4519 int userId = UserHandle.getCallingUserId();
4520
4521 long identityToken = clearCallingIdentity();
4522 try {
4523 UserAccounts userAccounts = getUserAccounts(userId);
4524 if (ArrayUtils.isEmpty(features)) {
4525 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4526 userAccounts, accountType, callingUid, opPackageName,
4527 true /* include managed not visible */);
4528 handleGetAccountsResult(
4529 response, accountsWithManagedNotVisible, opPackageName);
4530 return;
4531 }
4532
4533 IAccountManagerResponse retrieveAccountsResponse =
4534 new IAccountManagerResponse.Stub() {
4535 @Override
4536 public void onResult(Bundle value) throws RemoteException {
4537 Parcelable[] parcelables = value.getParcelableArray(
4538 AccountManager.KEY_ACCOUNTS);
4539 Account[] accounts = new Account[parcelables.length];
4540 for (int i = 0; i < parcelables.length; i++) {
4541 accounts[i] = (Account) parcelables[i];
4542 }
4543 handleGetAccountsResult(
4544 response, accounts, opPackageName);
4545 }
4546
4547 @Override
4548 public void onError(int errorCode, String errorMessage)
4549 throws RemoteException {
4550 // Will not be called in this case.
4551 }
4552 };
4553 new GetAccountsByTypeAndFeatureSession(
4554 userAccounts,
4555 retrieveAccountsResponse,
4556 accountType,
4557 features,
4558 callingUid,
4559 opPackageName,
4560 true /* include managed not visible */).bind();
4561 } finally {
4562 restoreCallingIdentity(identityToken);
4563 }
4564 }
4565
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004566 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004567 public void getAccountsByFeatures(
4568 IAccountManagerResponse response,
4569 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004570 String[] features,
4571 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004572 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004573 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004574 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4575 Log.v(TAG, "getAccounts: accountType " + type
4576 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004577 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004578 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004579 + ", pid " + Binder.getCallingPid());
4580 }
Fred Quintana382601f2010-03-25 12:25:10 -07004581 if (response == null) throw new IllegalArgumentException("response is null");
4582 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004583 int userId = UserHandle.getCallingUserId();
4584
Svetoslavf3f02ac2015-09-08 14:36:35 -07004585 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4586 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004587 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004588 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004589 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004590 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004591 try {
4592 response.onResult(result);
4593 } catch (RemoteException e) {
4594 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4595 }
4596 return;
4597 }
sunjianf29d5492017-05-11 15:42:31 -07004598
Fred Quintana33269202009-04-20 16:05:10 -07004599 long identityToken = clearCallingIdentity();
4600 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004601 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004602 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004603 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4604 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004605 Bundle result = new Bundle();
4606 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4607 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004608 return;
4609 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004610 new GetAccountsByTypeAndFeatureSession(
4611 userAccounts,
4612 response,
4613 type,
4614 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004615 callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004616 opPackageName,
4617 false /* include managed not visible */).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004618 } finally {
4619 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004620 }
4621 }
4622
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004623 @Override
4624 public void onAccountAccessed(String token) throws RemoteException {
4625 final int uid = Binder.getCallingUid();
4626 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4627 return;
4628 }
4629 final int userId = UserHandle.getCallingUserId();
4630 final long identity = Binder.clearCallingIdentity();
4631 try {
4632 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4633 if (Objects.equals(account.getAccessId(), token)) {
4634 // An app just accessed the account. At this point it knows about
4635 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004636 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004637 if (!hasAccountAccess(account, null, uid)) {
4638 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4639 uid, true);
4640 }
4641 }
4642 }
4643 } finally {
4644 Binder.restoreCallingIdentity(identity);
4645 }
4646 }
4647
Fred Quintanaa698f422009-04-08 19:14:54 -07004648 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004649 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004650 IAccountManagerResponse mResponse;
4651 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004652 final boolean mExpectActivityLaunch;
4653 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004654 final String mAccountName;
4655 // Indicates if we need to add auth details(like last credential time)
4656 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004657 // If set, we need to update the last authenticated time. This is
4658 // currently
4659 // used on
4660 // successful confirming credentials.
4661 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004662
Fred Quintana33269202009-04-20 16:05:10 -07004663 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004664 private int mNumRequestContinued = 0;
4665 private int mNumErrors = 0;
4666
Fred Quintana60307342009-03-24 22:48:12 -07004667 IAccountAuthenticator mAuthenticator = null;
4668
Fred Quintana8570f742010-02-18 10:32:54 -08004669 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004670 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004671
Amith Yamasani04e0d262012-02-14 11:50:53 -08004672 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004673 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4674 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004675 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4676 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4677 }
4678
4679 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4680 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4681 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004682 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004683 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004684 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004685 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004686 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004687 mResponse = response;
4688 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004689 mExpectActivityLaunch = expectActivityLaunch;
4690 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004691 mAccountName = accountName;
4692 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004693 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004694
Fred Quintanaa698f422009-04-08 19:14:54 -07004695 synchronized (mSessions) {
4696 mSessions.put(toString(), this);
4697 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004698 if (response != null) {
4699 try {
4700 response.asBinder().linkToDeath(this, 0 /* flags */);
4701 } catch (RemoteException e) {
4702 mResponse = null;
4703 binderDied();
4704 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004705 }
Fred Quintana60307342009-03-24 22:48:12 -07004706 }
4707
Fred Quintanaa698f422009-04-08 19:14:54 -07004708 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004709 if (mResponse == null) {
4710 // this session has already been closed
4711 return null;
4712 }
Fred Quintana60307342009-03-24 22:48:12 -07004713 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004714 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004715 return response;
4716 }
4717
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004718 /**
4719 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4720 * security policy.
4721 *
4722 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004723 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004724 * supplied entries in the system Settings app.
4725 */
tiansiminga8868bf2017-09-20 13:59:13 +08004726 protected boolean checkKeyIntent(int authUid, Intent intent) {
Jeff Sharkeyd722e782017-06-12 17:33:07 -06004727 intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4728 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4729 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4730 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004731 long bid = Binder.clearCallingIdentity();
4732 try {
4733 PackageManager pm = mContext.getPackageManager();
4734 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
tiansiminga8868bf2017-09-20 13:59:13 +08004735 if (resolveInfo == null) {
4736 return false;
4737 }
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004738 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4739 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004740 if (!isExportedSystemActivity(targetActivityInfo)
4741 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4742 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004743 String pkgName = targetActivityInfo.packageName;
4744 String activityName = targetActivityInfo.name;
4745 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4746 + "does not share a signature with the supplying authenticator (%s).";
tiansiminga8868bf2017-09-20 13:59:13 +08004747 Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
4748 return false;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004749 }
tiansiminga8868bf2017-09-20 13:59:13 +08004750 return true;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004751 } finally {
4752 Binder.restoreCallingIdentity(bid);
4753 }
4754 }
4755
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004756 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4757 String className = activityInfo.name;
4758 return "android".equals(activityInfo.packageName) &&
4759 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4760 || CantAddAccountActivity.class.getName().equals(className));
4761 }
4762
Fred Quintanaa698f422009-04-08 19:14:54 -07004763 private void close() {
4764 synchronized (mSessions) {
4765 if (mSessions.remove(toString()) == null) {
4766 // the session was already closed, so bail out now
4767 return;
4768 }
4769 }
4770 if (mResponse != null) {
4771 // stop listening for response deaths
4772 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4773
4774 // clear this so that we don't accidentally send any further results
4775 mResponse = null;
4776 }
4777 cancelTimeout();
4778 unbind();
4779 }
4780
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004781 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004782 public void binderDied() {
4783 mResponse = null;
4784 close();
4785 }
4786
4787 protected String toDebugString() {
4788 return toDebugString(SystemClock.elapsedRealtime());
4789 }
4790
4791 protected String toDebugString(long now) {
4792 return "Session: expectLaunch " + mExpectActivityLaunch
4793 + ", connected " + (mAuthenticator != null)
4794 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4795 + "/" + mNumErrors + ")"
4796 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4797 }
4798
Fred Quintana60307342009-03-24 22:48:12 -07004799 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004800 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4801 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4802 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004803 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004804 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004805 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004806 }
4807 }
4808
4809 private void unbind() {
4810 if (mAuthenticator != null) {
4811 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004812 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004813 }
4814 }
4815
Fred Quintana60307342009-03-24 22:48:12 -07004816 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004817 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004818 }
4819
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004820 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004821 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004822 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004823 try {
4824 run();
4825 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004826 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004827 "remote exception");
4828 }
Fred Quintana60307342009-03-24 22:48:12 -07004829 }
4830
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004831 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004832 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004833 mAuthenticator = null;
4834 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004835 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004836 try {
4837 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4838 "disconnected");
4839 } catch (RemoteException e) {
4840 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4841 Log.v(TAG, "Session.onServiceDisconnected: "
4842 + "caught RemoteException while responding", e);
4843 }
4844 }
Fred Quintana60307342009-03-24 22:48:12 -07004845 }
4846 }
4847
Fred Quintanab839afc2009-10-14 15:57:28 -07004848 public abstract void run() throws RemoteException;
4849
Fred Quintana60307342009-03-24 22:48:12 -07004850 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004851 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004852 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004853 try {
4854 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4855 "timeout");
4856 } catch (RemoteException e) {
4857 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4858 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4859 e);
4860 }
4861 }
Fred Quintana60307342009-03-24 22:48:12 -07004862 }
4863 }
4864
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004865 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004866 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004867 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004868 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004869 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004870 if (result != null) {
4871 boolean isSuccessfulConfirmCreds = result.getBoolean(
4872 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004873 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004874 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4875 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004876 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004877 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4878 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004879 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004880 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004881 if (needUpdate || mAuthDetailsRequired) {
4882 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4883 if (needUpdate && accountPresent) {
4884 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4885 }
4886 if (mAuthDetailsRequired) {
4887 long lastAuthenticatedTime = -1;
4888 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004889 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004890 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004891 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004892 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004893 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004894 lastAuthenticatedTime);
4895 }
4896 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004897 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004898 if (result != null
4899 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08004900 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004901 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08004902 intent)) {
4903 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
4904 "invalid intent in bundle returned");
4905 return;
4906 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004907 }
4908 if (result != null
4909 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004910 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4911 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004912 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4913 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004914 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4915 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004916 }
Fred Quintana60307342009-03-24 22:48:12 -07004917 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004918 IAccountManagerResponse response;
4919 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004920 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004921 response = mResponse;
4922 } else {
4923 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004924 }
Fred Quintana60307342009-03-24 22:48:12 -07004925 if (response != null) {
4926 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004927 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004928 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4929 Log.v(TAG, getClass().getSimpleName()
4930 + " calling onError() on response " + response);
4931 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004932 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004933 "null bundle returned");
4934 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004935 if (mStripAuthTokenFromResult) {
4936 result.remove(AccountManager.KEY_AUTHTOKEN);
4937 }
Fred Quintana56285a62010-12-02 14:20:51 -08004938 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4939 Log.v(TAG, getClass().getSimpleName()
4940 + " calling onResult() on response " + response);
4941 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004942 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4943 (intent == null)) {
4944 // All AccountManager error codes are greater than 0
4945 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4946 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4947 } else {
4948 response.onResult(result);
4949 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004950 }
Fred Quintana60307342009-03-24 22:48:12 -07004951 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004952 // if the caller is dead then there is no one to care about remote exceptions
4953 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4954 Log.v(TAG, "failure while notifying response", e);
4955 }
Fred Quintana60307342009-03-24 22:48:12 -07004956 }
4957 }
4958 }
Fred Quintana60307342009-03-24 22:48:12 -07004959
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004960 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004961 public void onRequestContinued() {
4962 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004963 }
4964
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004965 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004966 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004967 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004968 IAccountManagerResponse response = getResponseAndClose();
4969 if (response != null) {
4970 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004971 Log.v(TAG, getClass().getSimpleName()
4972 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004973 }
4974 try {
4975 response.onError(errorCode, errorMessage);
4976 } catch (RemoteException e) {
4977 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4978 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4979 }
4980 }
4981 } else {
4982 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4983 Log.v(TAG, "Session.onError: already closed");
4984 }
Fred Quintana60307342009-03-24 22:48:12 -07004985 }
4986 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004987
4988 /**
4989 * find the component name for the authenticator and initiate a bind
4990 * if no authenticator or the bind fails then return false, otherwise return true
4991 */
4992 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004993 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4994 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4995 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004996 if (authenticatorInfo == null) {
4997 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4998 Log.v(TAG, "there is no authenticator for " + authenticatorType
4999 + ", bailing out");
5000 }
5001 return false;
5002 }
5003
Jeff Sharkeyce18c812016-04-27 16:00:41 -06005004 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06005005 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07005006 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
5007 + " which isn't encryption aware");
5008 return false;
5009 }
5010
Fred Quintanab839afc2009-10-14 15:57:28 -07005011 Intent intent = new Intent();
5012 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
5013 intent.setComponent(authenticatorInfo.componentName);
5014 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5015 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
5016 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08005017 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005018 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07005019 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5020 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
5021 }
5022 return false;
5023 }
5024
Fred Quintanab839afc2009-10-14 15:57:28 -07005025 return true;
5026 }
Fred Quintana60307342009-03-24 22:48:12 -07005027 }
5028
Svet Ganov5d09c992016-09-07 09:57:41 -07005029 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07005030 MessageHandler(Looper looper) {
5031 super(looper);
5032 }
Costin Manolache3348f142009-09-29 18:58:36 -07005033
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07005034 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005035 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07005036 switch (msg.what) {
5037 case MESSAGE_TIMED_OUT:
5038 Session session = (Session)msg.obj;
5039 session.onTimedOut();
5040 break;
5041
Amith Yamasani5be347b2013-03-31 17:44:31 -07005042 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00005043 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07005044 break;
5045
Fred Quintana60307342009-03-24 22:48:12 -07005046 default:
5047 throw new IllegalStateException("unhandled message: " + msg.what);
5048 }
5049 }
5050 }
5051
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005052 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005053 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005054 }
5055
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005056 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005057 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005058 }
5059
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005060 /*
5061 * This function receives an opened writable database.
5062 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005063 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005064 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005065 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005066 }
5067
5068 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005069 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005070 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005071 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005072 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005073
5074 class LogRecordTask implements Runnable {
5075 private final String action;
5076 private final String tableName;
5077 private final long accountId;
5078 private final UserAccounts userAccount;
5079 private final int callingUid;
5080 private final long userDebugDbInsertionPoint;
5081
5082 LogRecordTask(final String action,
5083 final String tableName,
5084 final long accountId,
5085 final UserAccounts userAccount,
5086 final int callingUid,
5087 final long userDebugDbInsertionPoint) {
5088 this.action = action;
5089 this.tableName = tableName;
5090 this.accountId = accountId;
5091 this.userAccount = userAccount;
5092 this.callingUid = callingUid;
5093 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5094 }
5095
Andrew Scullc7770d62017-05-22 17:49:58 +01005096 @Override
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005097 public void run() {
5098 SQLiteStatement logStatement = userAccount.statementForLogging;
5099 logStatement.bindLong(1, accountId);
5100 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005101 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005102 logStatement.bindLong(4, callingUid);
5103 logStatement.bindString(5, tableName);
5104 logStatement.bindLong(6, userDebugDbInsertionPoint);
Tetsutoki Shiozawabe2d96a2017-10-24 18:44:00 +09005105 try {
5106 logStatement.execute();
5107 } catch (IllegalStateException e) {
5108 // Guard against crash, DB can already be closed
5109 // since this statement is executed on a handler thread
5110 Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
5111 + " action=" + action + " tableName=" + tableName + " Error: " + e);
5112 } finally {
5113 logStatement.clearBindings();
5114 }
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005115 }
5116 }
5117
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005118 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5119 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005120 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005121 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005122 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005123 }
5124
5125 /*
5126 * This should only be called once to compile the sql statement for logging
5127 * and to find the insertion point.
5128 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005129 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
5130 userAccount.debugDbInsertionPoint = userAccount.accountsDb
5131 .calculateDebugTableInsertionPoint();
5132 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005133 }
5134
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005135 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07005136 return asBinder();
5137 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005138
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005139 /**
5140 * Searches array of arguments for the specified string
5141 * @param args array of argument strings
5142 * @param value value to search for
5143 * @return true if the value is contained in the array
5144 */
5145 private static boolean scanArgs(String[] args, String value) {
5146 if (args != null) {
5147 for (String arg : args) {
5148 if (value.equals(arg)) {
5149 return true;
5150 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005151 }
5152 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005153 return false;
5154 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005155
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005156 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005157 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005158 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005159 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005160 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07005161
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005162 final List<UserInfo> users = getUserManager().getUsers();
5163 for (UserInfo user : users) {
5164 ipw.println("User " + user + ":");
5165 ipw.increaseIndent();
5166 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5167 ipw.println();
5168 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08005169 }
5170 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005171
Amith Yamasani04e0d262012-02-14 11:50:53 -08005172 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5173 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005174 if (isCheckinRequest) {
5175 // This is a checkin request. *Only* upload the account types and the count of
5176 // each.
5177 synchronized (userAccounts.dbLock) {
5178 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5179 }
5180 } else {
5181 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5182 Process.SYSTEM_UID, null /* packageName */, false);
5183 fout.println("Accounts: " + accounts.length);
5184 for (Account account : accounts) {
5185 fout.println(" " + account);
5186 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005187
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005188 // Add debug information.
5189 fout.println();
5190 synchronized (userAccounts.dbLock) {
5191 userAccounts.accountsDb.dumpDebugTable(fout);
5192 }
5193 fout.println();
5194 synchronized (mSessions) {
5195 final long now = SystemClock.elapsedRealtime();
5196 fout.println("Active Sessions: " + mSessions.size());
5197 for (Session session : mSessions.values()) {
5198 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005199 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005200 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005201
5202 fout.println();
5203 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Tony Mak6d14d772017-07-13 17:49:46 +08005204
5205 boolean isUserUnlocked;
5206 synchronized (mUsers) {
5207 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
5208 }
5209 // Following logs are printed only when user is unlocked.
5210 if (!isUserUnlocked) {
5211 return;
5212 }
5213 fout.println();
5214 synchronized (userAccounts.dbLock) {
5215 Map<Account, Map<String, Integer>> allVisibilityValues =
5216 userAccounts.accountsDb.findAllVisibilityValues();
5217 fout.println("Account visibility:");
5218 for (Account account : allVisibilityValues.keySet()) {
5219 fout.println(" " + account.name);
5220 Map<String, Integer> visibilities = allVisibilityValues.get(account);
5221 for (Entry<String, Integer> entry : visibilities.entrySet()) {
5222 fout.println(" " + entry.getKey() + ", " + entry.getValue());
5223 }
5224 }
5225 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005226 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005227 }
5228
Amith Yamasani04e0d262012-02-14 11:50:53 -08005229 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005230 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005231 long identityToken = clearCallingIdentity();
5232 try {
5233 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5234 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5235 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005236
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005237 if (intent.getComponent() != null &&
5238 GrantCredentialsPermissionActivity.class.getName().equals(
5239 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005240 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005241 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005242 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04005243 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5244 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005245
Fred Quintana33f889a2009-09-14 17:31:26 -07005246 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005247 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05005248 Notification n =
5249 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005250 .setWhen(0)
5251 .setSmallIcon(android.R.drawable.stat_sys_warning)
5252 .setColor(contextForUser.getColor(
5253 com.android.internal.R.color.system_notification_accent_color))
5254 .setContentTitle(String.format(notificationTitleFormat, account.name))
5255 .setContentText(message)
5256 .setContentIntent(PendingIntent.getActivityAsUser(
5257 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005258 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005259 .build();
Chris Wren717a8812017-03-31 15:34:39 -04005260 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005261 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005262 } finally {
5263 restoreCallingIdentity(identityToken);
5264 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005265 }
5266
Chris Wren717a8812017-03-31 15:34:39 -04005267 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005268 String packageName, int userId) {
5269 final long token = clearCallingIdentity();
5270 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005271 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005272 try {
Chris Wren717a8812017-03-31 15:34:39 -04005273 notificationManager.enqueueNotificationWithTag(packageName, packageName,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04005274 id.mTag, id.mId, notification, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005275 } catch (RemoteException e) {
5276 /* ignore - local call */
5277 }
5278 } finally {
5279 Binder.restoreCallingIdentity(token);
5280 }
Fred Quintana56285a62010-12-02 14:20:51 -08005281 }
5282
Chris Wren717a8812017-03-31 15:34:39 -04005283 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005284 cancelNotification(id, mContext.getPackageName(), user);
5285 }
5286
Chris Wren717a8812017-03-31 15:34:39 -04005287 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005288 long identityToken = clearCallingIdentity();
5289 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005290 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04005291 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005292 } catch (RemoteException e) {
5293 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005294 } finally {
5295 restoreCallingIdentity(identityToken);
5296 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005297 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005298
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005299 private boolean isPermittedForPackage(String packageName, int uid, int userId,
5300 String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005301 final long identity = Binder.clearCallingIdentity();
5302 try {
5303 IPackageManager pm = ActivityThread.getPackageManager();
5304 for (String perm : permissions) {
5305 if (pm.checkPermission(perm, packageName, userId)
5306 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005307 // Checks runtime permission revocation.
5308 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005309 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005310 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5311 return true;
5312 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005313 }
5314 }
5315 } catch (RemoteException e) {
5316 /* ignore - local call */
5317 } finally {
5318 Binder.restoreCallingIdentity(identity);
5319 }
5320 return false;
5321 }
5322
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005323 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5324 for (String perm : permissions) {
5325 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5326 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5327 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5328 }
5329 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005330 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005331 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5332 return true;
5333 }
5334 }
5335 }
5336 return false;
5337 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005338
Amith Yamasani67df64b2012-12-14 12:09:36 -08005339 private int handleIncomingUser(int userId) {
5340 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005341 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005342 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5343 } catch (RemoteException re) {
5344 // Shouldn't happen, local.
5345 }
5346 return userId;
5347 }
5348
Christopher Tateccbf84f2013-05-08 15:25:41 -07005349 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005350 String[] packages;
5351 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005352 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005353 packages = mPackageManager.getPackagesForUid(callingUid);
sunjian9ae597b62017-08-14 15:45:04 -07005354 if (packages == null) {
5355 Log.d(TAG, "No packages for callingUid " + callingUid);
Fred Quintana7be59642009-08-24 18:29:25 -07005356 return false;
5357 }
sunjian9ae597b62017-08-14 15:45:04 -07005358 for (String name : packages) {
5359 try {
5360 PackageInfo packageInfo =
5361 mPackageManager.getPackageInfo(name, 0 /* flags */);
5362 if (packageInfo != null
5363 && (packageInfo.applicationInfo.privateFlags
5364 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
5365 return true;
5366 }
5367 } catch (PackageManager.NameNotFoundException e) {
5368 Log.d(TAG, "Package not found " + e.getMessage());
5369 }
5370 }
5371 } finally {
5372 Binder.restoreCallingIdentity(identityToken);
Fred Quintana7be59642009-08-24 18:29:25 -07005373 }
5374 return false;
5375 }
5376
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005377 private boolean permissionIsGranted(
5378 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005379 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5380 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5381 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5382 }
5383 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005384 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005385
5386 if (isPrivileged(callerUid)) {
5387 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5388 Log.v(TAG, "Access to " + account + " granted calling uid "
5389 + callerUid + " privileged");
5390 }
5391 return true;
5392 }
5393 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5394 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5395 Log.v(TAG, "Access to " + account + " granted calling uid "
5396 + callerUid + " manages the account");
5397 }
5398 return true;
5399 }
5400 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5401 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5402 Log.v(TAG, "Access to " + account + " granted calling uid "
5403 + callerUid + " user granted access");
5404 }
5405 return true;
5406 }
5407
5408 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5409 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5410 }
5411
5412 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005413 }
5414
Svetoslavf3f02ac2015-09-08 14:36:35 -07005415 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5416 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005417 if (accountType == null) {
5418 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005419 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005420 return getTypesVisibleToCaller(callingUid, userId,
5421 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005422 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005423 }
5424
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005425 // Method checks visibility for applications targeing API level below {@link
5426 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005427 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005428 private boolean checkGetAccountsPermission(String packageName, int uid, int userId) {
5429 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005430 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5431 }
5432
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005433 private boolean checkReadContactsPermission(String packageName, int uid, int userId) {
5434 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS);
5435 }
5436
5437 // Heuristic to check that account type may be associated with some contacts data and
5438 // therefore READ_CONTACTS permission grants the access to account by default.
5439 private boolean accountTypeManagesContacts(String accountType, int userId) {
5440 if (accountType == null) {
5441 return false;
5442 }
5443 long identityToken = Binder.clearCallingIdentity();
5444 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5445 try {
5446 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5447 } finally {
5448 Binder.restoreCallingIdentity(identityToken);
5449 }
5450 // Check contacts related permissions for authenticator.
5451 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5452 : serviceInfos) {
5453 if (accountType.equals(serviceInfo.type.type)) {
5454 return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId,
5455 Manifest.permission.WRITE_CONTACTS);
5456 }
5457 }
5458 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005459 }
5460
5461 /**
5462 * Method checks package uid and signature with Authenticator which manages accountType.
5463 *
5464 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5465 * SIGNATURE_CHECK_MISMATCH otherwise.
5466 */
5467 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5468 if (accountType == null) {
5469 return SIGNATURE_CHECK_MISMATCH;
5470 }
5471
5472 long identityToken = Binder.clearCallingIdentity();
5473 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5474 try {
5475 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5476 } finally {
5477 Binder.restoreCallingIdentity(identityToken);
5478 }
5479 // Check for signature match with Authenticator.
5480 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5481 : serviceInfos) {
5482 if (accountType.equals(serviceInfo.type.type)) {
5483 if (serviceInfo.uid == callingUid) {
5484 return SIGNATURE_CHECK_UID_MATCH;
5485 }
5486 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5487 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5488 return SIGNATURE_CHECK_MATCH;
5489 }
5490 }
5491 }
5492 return SIGNATURE_CHECK_MISMATCH;
5493 }
5494
5495 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005496 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5497 if (accountType == null) {
5498 return false;
5499 } else {
5500 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5501 }
5502 }
5503
Svetoslavf3f02ac2015-09-08 14:36:35 -07005504 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5505 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005506 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005507 }
5508
5509 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005510 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005511 }
5512
5513 private List<String> getTypesForCaller(
5514 int callingUid, int userId, boolean isOtherwisePermitted) {
5515 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005516 long identityToken = Binder.clearCallingIdentity();
5517 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5518 try {
5519 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5520 } finally {
5521 Binder.restoreCallingIdentity(identityToken);
5522 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005523 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005524 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005525 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5526 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005527 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005528 }
5529 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005530 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005531 }
5532
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005533 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5534 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5535 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5536 if (account.name.equals(accountName)) {
5537 return true;
5538 }
5539 }
5540 }
5541 return false;
5542 }
5543
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005544 private static void checkManageUsersPermission(String message) {
5545 if (ActivityManager.checkComponentPermission(
5546 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5547 != PackageManager.PERMISSION_GRANTED) {
5548 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5549 }
5550 }
5551
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005552 private static void checkManageOrCreateUsersPermission(String message) {
5553 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5554 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5555 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5556 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5557 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5558 + message);
5559 }
5560 }
5561
Amith Yamasani04e0d262012-02-14 11:50:53 -08005562 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5563 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005564 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005565 return true;
5566 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005567 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005568 synchronized (accounts.dbLock) {
5569 synchronized (accounts.cacheLock) {
5570 long grantsCount;
5571 if (authTokenType != null) {
5572 grantsCount = accounts.accountsDb
5573 .findMatchingGrantsCount(callerUid, authTokenType, account);
5574 } else {
5575 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5576 account);
5577 }
5578 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005579
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005580 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5581 // TODO: Skip this check when running automated tests. Replace this
5582 // with a more general solution.
5583 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5584 + authTokenType + " by uid " + callerUid
5585 + " but ignoring since device is in test harness.");
5586 return true;
5587 }
5588 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005589 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005590 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005591 }
5592
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005593 private boolean isSystemUid(int callingUid) {
5594 String[] packages = null;
5595 long ident = Binder.clearCallingIdentity();
5596 try {
5597 packages = mPackageManager.getPackagesForUid(callingUid);
5598 } finally {
5599 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005600 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005601 if (packages != null) {
5602 for (String name : packages) {
5603 try {
5604 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5605 if (packageInfo != null
5606 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5607 != 0) {
5608 return true;
5609 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005610 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005611 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5612 }
5613 }
5614 } else {
5615 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005616 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005617 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005618 }
5619
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005620 /** Succeeds if any of the specified permissions are granted. */
5621 private void checkReadAccountsPermitted(
5622 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005623 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005624 int userId,
5625 String opPackageName) {
5626 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005627 String msg = String.format(
5628 "caller uid %s cannot access %s accounts",
5629 callingUid,
5630 accountType);
5631 Log.w(TAG, " " + msg);
5632 throw new SecurityException(msg);
5633 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005634 }
5635
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005636 private boolean canUserModifyAccounts(int userId, int callingUid) {
5637 // the managing app can always modify accounts
5638 if (isProfileOwner(callingUid)) {
5639 return true;
5640 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005641 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5642 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5643 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005644 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005645 return true;
5646 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005647
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005648 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5649 // the managing app can always modify accounts
5650 if (isProfileOwner(callingUid)) {
5651 return true;
5652 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005653 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5654 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005655 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005656 if (typesArray == null) {
5657 return true;
5658 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005659 for (String forbiddenType : typesArray) {
5660 if (forbiddenType.equals(accountType)) {
5661 return false;
5662 }
5663 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005664 return true;
5665 }
5666
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005667 private boolean isProfileOwner(int uid) {
5668 final DevicePolicyManagerInternal dpmi =
5669 LocalServices.getService(DevicePolicyManagerInternal.class);
5670 return (dpmi != null)
5671 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5672 }
5673
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005674 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005675 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5676 throws RemoteException {
5677 final int callingUid = getCallingUid();
5678
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005679 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005680 throw new SecurityException();
5681 }
5682
5683 if (value) {
5684 grantAppPermission(account, authTokenType, uid);
5685 } else {
5686 revokeAppPermission(account, authTokenType, uid);
5687 }
5688 }
5689
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005690 /**
5691 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5692 * <p>
5693 * Although this is public it can only be accessed via the AccountManagerService object
5694 * which is in the system. This means we don't need to protect it with permissions.
5695 * @hide
5696 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005697 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005698 if (account == null || authTokenType == null) {
5699 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005700 return;
5701 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005702 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005703 synchronized (accounts.dbLock) {
5704 synchronized (accounts.cacheLock) {
5705 long accountId = accounts.accountsDb.findDeAccountId(account);
5706 if (accountId >= 0) {
5707 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5708 }
5709 cancelNotification(
5710 getCredentialPermissionNotificationId(account, authTokenType, uid),
5711 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005712
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005713 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5714 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005715 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005716
5717 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5718 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5719 : mAppPermissionChangeListeners) {
5720 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5721 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005722 }
5723
5724 /**
5725 * Don't allow callers with the given uid permission to get credentials for
5726 * account/authTokenType.
5727 * <p>
5728 * Although this is public it can only be accessed via the AccountManagerService object
5729 * which is in the system. This means we don't need to protect it with permissions.
5730 * @hide
5731 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005732 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005733 if (account == null || authTokenType == null) {
5734 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005735 return;
5736 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005737 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005738 synchronized (accounts.dbLock) {
5739 synchronized (accounts.cacheLock) {
5740 accounts.accountsDb.beginTransaction();
5741 try {
5742 long accountId = accounts.accountsDb.findDeAccountId(account);
5743 if (accountId >= 0) {
5744 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5745 accountId, authTokenType, uid);
5746 accounts.accountsDb.setTransactionSuccessful();
5747 }
5748 } finally {
5749 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005750 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005751
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005752 cancelNotification(
5753 getCredentialPermissionNotificationId(account, authTokenType, uid),
5754 UserHandle.of(accounts.userId));
5755 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005756 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005757
5758 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5759 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5760 : mAppPermissionChangeListeners) {
5761 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5762 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005763 }
Fred Quintana56285a62010-12-02 14:20:51 -08005764
Amith Yamasani04e0d262012-02-14 11:50:53 -08005765 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5766 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005767 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005768 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005769 for (Account curAccount : oldAccountsForType) {
5770 if (!curAccount.equals(account)) {
5771 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005772 }
5773 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005774 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005775 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005776 } else {
5777 Account[] newAccountsForType = new Account[newAccountsList.size()];
5778 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005779 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005780 }
Fred Quintana56285a62010-12-02 14:20:51 -08005781 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005782 accounts.userDataCache.remove(account);
5783 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005784 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005785 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005786 }
5787
5788 /**
5789 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005790 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5791 * processes and if you will return this account to apps you should return the result.
5792 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005793 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005794 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005795 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005796 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5797 Account[] newAccountsForType = new Account[oldLength + 1];
5798 if (accountsForType != null) {
5799 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005800 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005801 String token = account.getAccessId() != null ? account.getAccessId()
5802 : UUID.randomUUID().toString();
5803 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005804 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005805 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005806 }
5807
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005808 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005809 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005810 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005811 String visibilityFilterPackage = callingPackage;
5812 if (visibilityFilterPackage == null) {
5813 visibilityFilterPackage = getPackageNameForUid(callingUid);
5814 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005815 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005816 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005817 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005818 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5819 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5820 || (includeManagedNotVisible
5821 && (visibility
5822 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5823 firstPass.put(account, visibility);
5824 }
5825 }
5826 Map<Account, Integer> secondPass =
5827 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5828
5829 Account[] filtered = new Account[secondPass.size()];
5830 filtered = secondPass.keySet().toArray(filtered);
5831 return filtered;
5832 }
5833
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005834 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005835 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005836 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005837 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005838 // first part is to filter shared accounts.
5839 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005840 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005841 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005842 return unfiltered;
5843 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005844 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005845 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005846 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005847 if (packages == null) {
5848 packages = new String[] {};
5849 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005850 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005851 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005852 // This might be a temporary way to specify a visible list
5853 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005854 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5855 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005856 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005857 return unfiltered;
5858 }
5859 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005860 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005861 if (ArrayUtils.isEmpty(sharedAccounts)) {
5862 return unfiltered;
5863 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005864 String requiredAccountType = "";
5865 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005866 // If there's an explicit callingPackage specified, check if that package
5867 // opted in to see restricted accounts.
5868 if (callingPackage != null) {
5869 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005870 if (pi != null && pi.restrictedAccountType != null) {
5871 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005872 }
5873 } else {
5874 // Otherwise check if the callingUid has a package that has opted in
5875 for (String packageName : packages) {
5876 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5877 if (pi != null && pi.restrictedAccountType != null) {
5878 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005879 break;
5880 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005881 }
5882 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005883 } catch (NameNotFoundException e) {
5884 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005885 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005886 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005887 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5888 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005889 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005890 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005891 } else {
5892 boolean found = false;
5893 for (Account shared : sharedAccounts) {
5894 if (shared.equals(account)) {
5895 found = true;
5896 break;
5897 }
5898 }
5899 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005900 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005901 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005902 }
5903 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005904 return filtered;
5905 } else {
5906 return unfiltered;
5907 }
5908 }
5909
Amith Yamasani27db4682013-03-30 17:07:47 -07005910 /*
5911 * packageName can be null. If not null, it should be used to filter out restricted accounts
5912 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005913 *
5914 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5915 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005916 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005917 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005918 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005919 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005920 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5921 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005922 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005923 Account[] accounts;
5924 synchronized (userAccounts.cacheLock) {
5925 accounts = userAccounts.accountCache.get(accountType);
5926 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005927 if (accounts == null) {
5928 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005929 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005930 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5931 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005932 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005933 } else {
5934 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005935 Account[] accountsArray;
5936 synchronized (userAccounts.cacheLock) {
5937 for (Account[] accounts : userAccounts.accountCache.values()) {
5938 totalLength += accounts.length;
5939 }
5940 if (totalLength == 0) {
5941 return EMPTY_ACCOUNT_ARRAY;
5942 }
5943 accountsArray = new Account[totalLength];
5944 totalLength = 0;
5945 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5946 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5947 accountsOfType.length);
5948 totalLength += accountsOfType.length;
5949 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005950 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005951 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005952 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005953 }
5954 }
5955
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005956 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005957 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005958 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005959 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005960 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005961 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005962 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005963 }
5964 if (value == null) {
5965 userDataForAccount.remove(key);
5966 } else {
5967 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005968 }
5969 }
5970
Carlos Valdivia91979be2015-05-22 14:11:35 -07005971 protected String readCachedTokenInternal(
5972 UserAccounts accounts,
5973 Account account,
5974 String tokenType,
5975 String callingPackage,
5976 byte[] pkgSigDigest) {
Dmitry Dementyev18f0ca92017-06-12 17:56:47 -07005977 synchronized (accounts.cacheLock) {
5978 return accounts.accountTokenCaches.get(
5979 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07005980 }
5981 }
5982
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005983 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005984 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005985 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005986 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005987 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005988 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005989 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005990 }
5991 if (value == null) {
5992 authTokensForAccount.remove(key);
5993 } else {
5994 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005995 }
5996 }
5997
Amith Yamasani04e0d262012-02-14 11:50:53 -08005998 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5999 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006000 // Fast path - check if account is already cached
6001 synchronized (accounts.cacheLock) {
6002 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6003 if (authTokensForAccount != null) {
6004 return authTokensForAccount.get(authTokenType);
6005 }
6006 }
6007 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07006008 synchronized (accounts.dbLock) {
6009 synchronized (accounts.cacheLock) {
6010 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6011 if (authTokensForAccount == null) {
6012 // need to populate the cache for this account
6013 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6014 accounts.authTokenCache.put(account, authTokensForAccount);
6015 }
6016 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08006017 }
Fred Quintana56285a62010-12-02 14:20:51 -08006018 }
6019 }
6020
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006021 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
6022 Map<String, String> userDataForAccount;
6023 // Fast path - check if data is already cached
6024 synchronized (accounts.cacheLock) {
6025 userDataForAccount = accounts.userDataCache.get(account);
6026 }
6027 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00006028 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006029 synchronized (accounts.dbLock) {
6030 synchronized (accounts.cacheLock) {
6031 userDataForAccount = accounts.userDataCache.get(account);
6032 if (userDataForAccount == null) {
6033 // need to populate the cache for this account
6034 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6035 accounts.userDataCache.put(account, userDataForAccount);
6036 }
6037 }
6038 }
Fred Quintana56285a62010-12-02 14:20:51 -08006039 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00006040 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08006041 }
6042
Kenny Guy07ad8dc2014-09-01 20:56:12 +01006043 private Context getContextForUser(UserHandle user) {
6044 try {
6045 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
6046 } catch (NameNotFoundException e) {
6047 // Default to mContext, not finding the package system is running as is unlikely.
6048 return mContext;
6049 }
6050 }
Sandra Kwan78812282015-11-04 11:19:47 -08006051
6052 private void sendResponse(IAccountManagerResponse response, Bundle result) {
6053 try {
6054 response.onResult(result);
6055 } catch (RemoteException e) {
6056 // if the caller is dead then there is no one to care about remote
6057 // exceptions
6058 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6059 Log.v(TAG, "failure while notifying response", e);
6060 }
6061 }
6062 }
6063
6064 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6065 String errorMessage) {
6066 try {
6067 response.onError(errorCode, errorMessage);
6068 } catch (RemoteException e) {
6069 // if the caller is dead then there is no one to care about remote
6070 // exceptions
6071 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6072 Log.v(TAG, "failure while notifying response", e);
6073 }
6074 }
6075 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006076
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006077 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07006078 private final Object mLock = new Object();
6079
6080 @GuardedBy("mLock")
6081 private AccountManagerBackupHelper mBackupHelper;
6082
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006083 @Override
6084 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6085 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6086 if (account == null) {
6087 Slog.w(TAG, "account cannot be null");
6088 return;
6089 }
6090 if (packageName == null) {
6091 Slog.w(TAG, "packageName cannot be null");
6092 return;
6093 }
6094 if (userId < UserHandle.USER_SYSTEM) {
6095 Slog.w(TAG, "user id must be concrete");
6096 return;
6097 }
6098 if (callback == null) {
6099 Slog.w(TAG, "callback cannot be null");
6100 return;
6101 }
6102
Dmitry Dementyev7b3ea132017-05-10 12:45:02 -07006103 int visibility =
6104 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6105 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6106 Slog.w(TAG, "requestAccountAccess: account is hidden");
6107 return;
6108 }
6109
Svet Ganovf6d424f12016-09-20 20:18:53 -07006110 if (AccountManagerService.this.hasAccountAccess(account, packageName,
6111 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006112 Bundle result = new Bundle();
6113 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6114 callback.sendResult(result);
6115 return;
6116 }
6117
6118 final int uid;
6119 try {
6120 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6121 } catch (NameNotFoundException e) {
6122 Slog.e(TAG, "Unknown package " + packageName);
6123 return;
6124 }
6125
6126 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006127 final UserAccounts userAccounts;
6128 synchronized (mUsers) {
6129 userAccounts = mUsers.get(userId);
6130 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04006131 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006132 doNotification(userAccounts, account, null, intent, packageName, userId);
6133 }
6134
6135 @Override
6136 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6137 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6138 mAppPermissionChangeListeners.add(listener);
6139 }
6140
6141 @Override
6142 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6143 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006144 }
Svet Ganov5d09c992016-09-07 09:57:41 -07006145
6146 @Override
6147 public byte[] backupAccountAccessPermissions(int userId) {
6148 synchronized (mLock) {
6149 if (mBackupHelper == null) {
6150 mBackupHelper = new AccountManagerBackupHelper(
6151 AccountManagerService.this, this);
6152 }
6153 return mBackupHelper.backupAccountAccessPermissions(userId);
6154 }
6155 }
6156
6157 @Override
6158 public void restoreAccountAccessPermissions(byte[] data, int userId) {
6159 synchronized (mLock) {
6160 if (mBackupHelper == null) {
6161 mBackupHelper = new AccountManagerBackupHelper(
6162 AccountManagerService.this, this);
6163 }
6164 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6165 }
6166 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006167 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07006168
6169 @VisibleForTesting
6170 static class Injector {
6171 private final Context mContext;
6172
6173 public Injector(Context context) {
6174 mContext = context;
6175 }
6176
6177 Looper getMessageHandlerLooper() {
6178 ServiceThread serviceThread = new ServiceThread(TAG,
6179 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6180 serviceThread.start();
6181 return serviceThread.getLooper();
6182 }
6183
6184 Context getContext() {
6185 return mContext;
6186 }
6187
6188 void addLocalService(AccountManagerInternal service) {
6189 LocalServices.addService(AccountManagerInternal.class, service);
6190 }
6191
6192 String getDeDatabaseName(int userId) {
6193 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6194 AccountsDb.DE_DATABASE_NAME);
6195 return databaseFile.getPath();
6196 }
6197
6198 String getCeDatabaseName(int userId) {
6199 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6200 AccountsDb.CE_DATABASE_NAME);
6201 return databaseFile.getPath();
6202 }
6203
6204 String getPreNDatabaseName(int userId) {
6205 File systemDir = Environment.getDataSystemDirectory();
6206 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6207 PRE_N_DATABASE_NAME);
6208 if (userId == 0) {
6209 // Migrate old file, if it exists, to the new location.
6210 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006211 // accidentally created in the old location,
6212 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07006213 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6214 if (oldFile.exists() && !databaseFile.exists()) {
6215 // Check for use directory; create if it doesn't exist, else renameTo will fail
6216 File userDir = Environment.getUserSystemDirectory(userId);
6217 if (!userDir.exists()) {
6218 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006219 throw new IllegalStateException(
6220 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006221 }
6222 }
6223 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006224 throw new IllegalStateException(
6225 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006226 }
6227 }
6228 }
6229 return databaseFile.getPath();
6230 }
6231
6232 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6233 return new AccountAuthenticatorCache(mContext);
6234 }
6235
6236 INotificationManager getNotificationManager() {
6237 return NotificationManager.getService();
6238 }
6239 }
Chris Wren717a8812017-03-31 15:34:39 -04006240
Andrew Scullc7770d62017-05-22 17:49:58 +01006241 private static class NotificationId {
Chris Wren717a8812017-03-31 15:34:39 -04006242 final String mTag;
6243 private final int mId;
6244
6245 NotificationId(String tag, int type) {
6246 mTag = tag;
6247 mId = type;
6248 }
6249 }
Fred Quintana60307342009-03-24 22:48:12 -07006250}