blob: 9c60b8c00019f7fd67f35689e07bafa3dbdfe6bd [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;
Dan Cashman303c4bb2018-04-10 07:41:16 -070061import android.content.pm.PackageManagerInternal;
62import android.content.pm.PackageParser;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070063import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070064import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070065import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070066import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070067import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070068import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070069import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070070import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070071import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080072import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070073import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070074import android.os.IBinder;
75import android.os.Looper;
76import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070077import android.os.Parcel;
sunjianf29d5492017-05-11 15:42:31 -070078import android.os.Parcelable;
Amith Yamasani27db4682013-03-30 17:07:47 -070079import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070080import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070081import android.os.RemoteException;
Hongming Jin8e2bfc12018-05-30 11:01:06 -070082import android.os.ResultReceiver;
83import android.os.ShellCallback;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080084import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070085import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070086import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070087import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070088import android.text.TextUtils;
89import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070090import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070091import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080092import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070093import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070094
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070095import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070096import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070097import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070098import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040099import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500100import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -0800101import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600102import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800103import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -0700104import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +0000105import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700106import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600107import com.android.server.SystemService;
108
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700109import com.google.android.collect.Lists;
110import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700111
Oscar Montemayora8529f62009-11-18 10:14:20 -0800112import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700113import java.io.FileDescriptor;
114import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800115import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700116import java.security.MessageDigest;
117import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700118import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700119import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800120import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700121import java.util.Collection;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700122import java.util.Collections;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700123import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700124import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700125import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800126import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700127import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800128import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800129import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700130import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700131import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700132import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700133import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700134import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700135
Fred Quintana60307342009-03-24 22:48:12 -0700136/**
137 * A system service that provides account, password, and authtoken management for all
138 * accounts on the device. Some of these calls are implemented with the help of the corresponding
139 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
140 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700141 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700142 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700143 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700144public class AccountManagerService
145 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800146 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700147 private static final String TAG = "AccountManagerService";
148
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600149 public static class Lifecycle extends SystemService {
150 private AccountManagerService mService;
151
152 public Lifecycle(Context context) {
153 super(context);
154 }
155
156 @Override
157 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700158 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600159 publishBinderService(Context.ACCOUNT_SERVICE, mService);
160 }
161
162 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600163 public void onUnlockUser(int userHandle) {
164 mService.onUnlockUser(userHandle);
165 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700166
167 @Override
Fyodor Kupolovce25ed22017-05-04 11:44:31 -0700168 public void onStopUser(int userHandle) {
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700169 Slog.i(TAG, "onStopUser " + userHandle);
170 mService.purgeUserData(userHandle);
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700171 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600172 }
173
Svet Ganov5d09c992016-09-07 09:57:41 -0700174 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700175
Fred Quintana56285a62010-12-02 14:20:51 -0800176 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700177 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700178 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700179 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800180
Svet Ganov5d09c992016-09-07 09:57:41 -0700181 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700182
Fred Quintana60307342009-03-24 22:48:12 -0700183 // Messages that can be sent on mHandler
184 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700185 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700186
Fred Quintana56285a62010-12-02 14:20:51 -0800187 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700188 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700189 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800190
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800191 private static final int SIGNATURE_CHECK_MISMATCH = 0;
192 private static final int SIGNATURE_CHECK_MATCH = 1;
193 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
194
Carlos Valdivia91979be2015-05-22 14:11:35 -0700195 static {
196 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800197 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
198 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700199 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700200
201 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700202
Amith Yamasani04e0d262012-02-14 11:50:53 -0800203 static class UserAccounts {
204 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700205 final AccountsDb accountsDb;
Chris Wren717a8812017-03-31 15:34:39 -0400206 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
207 credentialsPermissionNotificationIds = new HashMap<>();
208 private final HashMap<Account, NotificationId> signinRequiredNotificationIds
209 = new HashMap<>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700210 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700211 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800212 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700213 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800214 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700215 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800216 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700217 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700218 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700219 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700220 /** protected by the {@link #cacheLock} */
221 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700222
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700223 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700224 * type -> (packageName -> number of active receivers)
225 * type == null is used to get notifications about all account types
226 */
227 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800228
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700229 /**
230 * protected by the {@link #cacheLock}
231 *
232 * Caches the previous names associated with an account. Previous names
233 * should be cached because we expect that when an Account is renamed,
234 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
235 * want to know if the accounts they care about have been renamed.
236 *
237 * The previous names are wrapped in an {@link AtomicReference} so that
238 * we can distinguish between those accounts with no previous names and
239 * those whose previous names haven't been cached (yet).
240 */
241 private final HashMap<Account, AtomicReference<String>> previousNameCache =
242 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800243
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700244 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700245 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700246
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700247 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800248 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700249 synchronized (dbLock) {
250 synchronized (cacheLock) {
251 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
252 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800253 }
254 }
255 }
256
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700257 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600258 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700259 // Not thread-safe. Only use in synchronized context
260 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700261 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
262 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800263
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700264 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700265 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700266
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700267 /**
268 * This should only be called by system code. One should only call this after the service
269 * has started.
270 * @return a reference to the AccountManagerService instance
271 * @hide
272 */
273 public static AccountManagerService getSingleton() {
274 return sThis.get();
275 }
Fred Quintana60307342009-03-24 22:48:12 -0700276
Fyodor Kupolovda993802016-09-21 14:47:10 -0700277 public AccountManagerService(Injector injector) {
278 mInjector = injector;
279 mContext = injector.getContext();
280 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700281 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700282 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
283 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800284 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700285
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700286 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800287
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800288 IntentFilter intentFilter = new IntentFilter();
289 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
290 intentFilter.addDataScheme("package");
291 mContext.registerReceiver(new BroadcastReceiver() {
292 @Override
293 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700294 // Don't delete accounts when updating a authenticator's
295 // package.
296 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700297 /* Purging data requires file io, don't block the main thread. This is probably
298 * less than ideal because we are introducing a race condition where old grants
299 * could be exercised until they are purged. But that race condition existed
300 * anyway with the broadcast receiver.
301 *
302 * Ideally, we would completely clear the cache, purge data from the database,
303 * and then rebuild the cache. All under the cache lock. But that change is too
304 * large at this point.
305 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800306 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700307 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700308 @Override
309 public void run() {
310 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800311 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800312 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700313 }
314 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700315 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700316 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800317 }
318 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800319
Fyodor Kupolovda993802016-09-21 14:47:10 -0700320 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700321
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700322 IntentFilter userFilter = new IntentFilter();
323 userFilter.addAction(Intent.ACTION_USER_REMOVED);
324 mContext.registerReceiverAsUser(new BroadcastReceiver() {
325 @Override
326 public void onReceive(Context context, Intent intent) {
327 String action = intent.getAction();
328 if (Intent.ACTION_USER_REMOVED.equals(action)) {
329 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
330 if (userId < 1) return;
331 Slog.i(TAG, "User " + userId + " removed");
332 purgeUserData(userId);
333 }
334 }
335 }, UserHandle.ALL, userFilter, null, null);
336
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700337 // Need to cancel account request notifications if the update/install can access the account
338 new PackageMonitor() {
339 @Override
340 public void onPackageAdded(String packageName, int uid) {
341 // Called on a handler, and running as the system
342 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
343 }
344
345 @Override
346 public void onPackageUpdateFinished(String packageName, int uid) {
347 // Called on a handler, and running as the system
348 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
349 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700350 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700351
352 // Cancel account request notification if an app op was preventing the account access
353 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
354 new AppOpsManager.OnOpChangedInternalListener() {
355 @Override
356 public void onOpChanged(int op, String packageName) {
357 try {
358 final int userId = ActivityManager.getCurrentUser();
359 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
360 final int mode = mAppOpsManager.checkOpNoThrow(
361 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
362 if (mode == AppOpsManager.MODE_ALLOWED) {
363 final long identity = Binder.clearCallingIdentity();
364 try {
365 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
366 } finally {
367 Binder.restoreCallingIdentity(identity);
368 }
369 }
370 } catch (NameNotFoundException e) {
371 /* ignore */
372 }
373 }
374 });
375
376 // Cancel account request notification if a permission was preventing the account access
377 mPackageManager.addOnPermissionsChangeListener(
378 (int uid) -> {
379 Account[] accounts = null;
380 String[] packageNames = mPackageManager.getPackagesForUid(uid);
381 if (packageNames != null) {
382 final int userId = UserHandle.getUserId(uid);
383 final long identity = Binder.clearCallingIdentity();
384 try {
385 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800386 // if app asked for permission we need to cancel notification even
387 // for O+ applications.
388 if (mPackageManager.checkPermission(
389 Manifest.permission.GET_ACCOUNTS,
390 packageName) != PackageManager.PERMISSION_GRANTED) {
391 continue;
392 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700393
394 if (accounts == null) {
395 accounts = getAccountsAsUser(null, userId, "android");
396 if (ArrayUtils.isEmpty(accounts)) {
397 return;
398 }
399 }
400
401 for (Account account : accounts) {
402 cancelAccountAccessRequestNotificationIfNeeded(
403 account, uid, packageName, true);
404 }
405 }
406 } finally {
407 Binder.restoreCallingIdentity(identity);
408 }
409 }
410 });
411 }
412
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700413
414 boolean getBindInstantServiceAllowed(int userId) {
415 return mAuthenticatorCache.getBindInstantServiceAllowed(userId);
416 }
417
418 void setBindInstantServiceAllowed(int userId, boolean allowed) {
419 mAuthenticatorCache.setBindInstantServiceAllowed(userId, allowed);
420 }
421
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700422 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
423 boolean checkAccess) {
424 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
425 for (Account account : accounts) {
426 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
427 }
428 }
429
430 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
431 boolean checkAccess) {
432 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
433 for (Account account : accounts) {
434 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
435 }
436 }
437
438 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
439 boolean checkAccess) {
440 String[] packageNames = mPackageManager.getPackagesForUid(uid);
441 if (packageNames != null) {
442 for (String packageName : packageNames) {
443 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
444 packageName, checkAccess);
445 }
446 }
447 }
448
449 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
450 int uid, String packageName, boolean checkAccess) {
451 if (!checkAccess || hasAccountAccess(account, packageName,
452 UserHandle.getUserHandleForUid(uid))) {
453 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700454 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700455 UserHandle.getUserHandleForUid(uid));
456 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800457 }
458
Dianne Hackborn164371f2013-10-01 19:10:13 -0700459 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800460 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800461 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800462 Bundle.setDefusable(extras, true);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700463 int callingUid = Binder.getCallingUid();
464 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800465 if (Log.isLoggable(TAG, Log.VERBOSE)) {
466 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
467 + ", pid " + Binder.getCallingPid());
468 }
469 Preconditions.checkNotNull(account, "account cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800470 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
471 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
472 callingUid, account.type);
473 throw new SecurityException(msg);
474 }
475 /*
476 * Child users are not allowed to add accounts. Only the accounts that are shared by the
477 * parent profile can be added to child profile.
478 *
479 * TODO: Only allow accounts that were shared to be added by a limited user.
480 */
481 // fails if the account already exists
482 long identityToken = clearCallingIdentity();
483 try {
484 UserAccounts accounts = getUserAccounts(userId);
485 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800486 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800487 } finally {
488 restoreCallingIdentity(identityToken);
489 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700490 }
491
492 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800493 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
494 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800495 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700496 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800497 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700498 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800499
500 if ((accountType != null && !managedTypes.contains(accountType))
501 || (accountType == null && !isSystemUid)) {
502 throw new SecurityException(
503 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
504 + callingUid + " with packageName=" + packageName);
505 }
506 if (accountType != null) {
507 managedTypes = new ArrayList<String>();
508 managedTypes.add(accountType);
509 }
510
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800511 long identityToken = clearCallingIdentity();
512 try {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700513 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800514 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700515 accounts);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800516 } finally {
517 restoreCallingIdentity(identityToken);
518 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800519 }
520
521 /*
522 * accountTypes may not be null
523 */
524 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
525 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700526 if (!packageExistsForUser(packageName, accounts.userId)) {
527 Log.d(TAG, "Package not found " + packageName);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800528 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800529 }
530
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800531 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800532 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700533 synchronized (accounts.dbLock) {
534 synchronized (accounts.cacheLock) {
535 final Account[] accountsOfType = accounts.accountCache.get(accountType);
536 if (accountsOfType != null) {
537 for (Account account : accountsOfType) {
538 result.put(account,
539 resolveAccountVisibility(account, packageName, accounts));
540 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800541 }
542 }
543 }
544 }
545 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800546 }
547
548 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800549 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700550 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700551 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700552 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800553 if (!isAccountManagedByCaller(account.type, callingUid, userId)
554 && !isSystemUid(callingUid)) {
555 String msg =
556 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700557 throw new SecurityException(msg);
558 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700559
560 long identityToken = clearCallingIdentity();
561 try {
562 UserAccounts accounts = getUserAccounts(userId);
563 synchronized (accounts.dbLock) {
564 synchronized (accounts.cacheLock) {
565 return getPackagesAndVisibilityForAccountLocked(account, accounts);
566 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700567 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700568 } finally {
569 restoreCallingIdentity(identityToken);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700570 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700571
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800572 }
573
574 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700575 * Returns Map with all package names and visibility values for given account.
576 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800577 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800578 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800579 * @param accounts UserAccount that currently hosts the account and application
580 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700581 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800582 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700583 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800584 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700585 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
586 if (accountVisibility == null) {
587 Log.d(TAG, "Visibility was not initialized");
588 accountVisibility = new HashMap<>();
589 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800590 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700591 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700592 }
593
594 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700595 public int getAccountVisibility(Account account, String packageName) {
596 Preconditions.checkNotNull(account, "account cannot be null");
597 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800598 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700599 int userId = UserHandle.getCallingUserId();
600 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800601 && !isSystemUid(callingUid)) {
602 String msg = String.format(
603 "uid %s cannot get secrets for accounts of type: %s",
604 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700605 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800606 throw new SecurityException(msg);
607 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700608 long identityToken = clearCallingIdentity();
609 try {
610 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyevcbe1bd12017-04-25 17:02:47 -0700611 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
612 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
613 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
614 return visibility;
615 } else {
616 return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
617 }
618 }
619 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) {
620 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
621 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
622 return visibility;
623 } else {
624 return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
625 }
626 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700627 return resolveAccountVisibility(account, packageName, accounts);
628 } finally {
629 restoreCallingIdentity(identityToken);
630 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800631 }
632
633 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800634 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800635 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800636 * @param account The account to check visibility.
637 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800638 * @param accounts UserAccount that currently hosts the account and application
639 *
640 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
641 *
642 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700643 private int getAccountVisibilityFromCache(Account account, String packageName,
644 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700645 synchronized (accounts.cacheLock) {
646 Map<String, Integer> accountVisibility =
647 getPackagesAndVisibilityForAccountLocked(account, accounts);
648 Integer visibility = accountVisibility.get(packageName);
649 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800650 }
651 }
652
653 /**
654 * Method which handles default values for Account visibility.
655 *
656 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800657 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800658 * @param accounts UserAccount that currently hosts the account and application
659 *
660 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
661 *
662 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800663 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800664 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800665 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800666 int uid = -1;
667 try {
668 long identityToken = clearCallingIdentity();
669 try {
670 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
671 } finally {
672 restoreCallingIdentity(identityToken);
673 }
674 } catch (NameNotFoundException e) {
675 Log.d(TAG, "Package not found " + e.getMessage());
676 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800677 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800678
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800679 // System visibility can not be restricted.
680 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
681 return AccountManager.VISIBILITY_VISIBLE;
682 }
683
684 int signatureCheckResult =
685 checkPackageSignature(account.type, uid, accounts.userId);
686
687 // Authenticator can not restrict visibility to itself.
688 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
689 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
690 }
691
692 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700693 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800694
695 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
696 return visibility;
697 }
698
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700699 boolean isPrivileged = isPermittedForPackage(packageName, uid, accounts.userId,
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800700 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
701
702 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800703 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800704 return AccountManager.VISIBILITY_VISIBLE;
705 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800706
707 boolean preO = isPreOApplication(packageName);
708 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700709 || (preO && checkGetAccountsPermission(packageName, uid, accounts.userId))
710 || (checkReadContactsPermission(packageName, uid, accounts.userId)
711 && accountTypeManagesContacts(account.type, accounts.userId))
712 || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800713 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
714 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700715 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800716 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800717 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
718 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
719 }
720 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700721 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800722 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800723 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
724 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
725 }
726 }
727 return visibility;
728 }
729
730 /**
731 * Checks targetSdk for a package;
732 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800733 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800734 *
735 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
736 * undefined
737 */
738 private boolean isPreOApplication(String packageName) {
739 try {
740 long identityToken = clearCallingIdentity();
741 ApplicationInfo applicationInfo;
742 try {
743 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
744 } finally {
745 restoreCallingIdentity(identityToken);
746 }
747
748 if (applicationInfo != null) {
749 int version = applicationInfo.targetSdkVersion;
750 return version < android.os.Build.VERSION_CODES.O;
751 }
752 return true;
753 } catch (NameNotFoundException e) {
754 Log.d(TAG, "Package not found " + e.getMessage());
755 return true;
756 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800757 }
758
759 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700760 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
761 Preconditions.checkNotNull(account, "account cannot be null");
762 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800763 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700764 int userId = UserHandle.getCallingUserId();
765 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800766 && !isSystemUid(callingUid)) {
767 String msg = String.format(
768 "uid %s cannot get secrets for accounts of type: %s",
769 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700770 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800771 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700772 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700773 long identityToken = clearCallingIdentity();
774 try {
775 UserAccounts accounts = getUserAccounts(userId);
776 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700777 accounts);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700778 } finally {
779 restoreCallingIdentity(identityToken);
780 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700781 }
782
sunjian066aa5e2017-06-05 12:16:59 -0700783 private boolean isVisible(int visibility) {
784 return visibility == AccountManager.VISIBILITY_VISIBLE ||
785 visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
786 }
787
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700788 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800789 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700790 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800791 * @param account Account to update visibility.
792 * @param packageName Package name for which visibility is updated.
793 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800794 * @param notify if the flag is set applications will get notification about visibility change
795 * @param accounts UserAccount that currently hosts the account and application
796 *
797 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700798 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800799 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800800 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700801 synchronized (accounts.dbLock) {
802 synchronized (accounts.cacheLock) {
803 Map<String, Integer> packagesToVisibility;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700804 List<String> accountRemovedReceivers;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700805 if (notify) {
806 if (isSpecialPackageKey(packageName)) {
807 packagesToVisibility =
808 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700809 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700810 } else {
811 if (!packageExistsForUser(packageName, accounts.userId)) {
812 return false; // package is not installed.
813 }
814 packagesToVisibility = new HashMap<>();
815 packagesToVisibility.put(packageName,
816 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700817 accountRemovedReceivers = new ArrayList<>();
818 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
819 accountRemovedReceivers.add(packageName);
820 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700821 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800822 } else {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700823 // Notifications will not be send - only used during add account.
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700824 if (!isSpecialPackageKey(packageName) &&
825 !packageExistsForUser(packageName, accounts.userId)) {
826 // package is not installed and not meta value.
827 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100828 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700829 packagesToVisibility = Collections.emptyMap();
830 accountRemovedReceivers = Collections.emptyList();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800831 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700832
833 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800834 return false;
835 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800836
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700837 if (notify) {
838 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
839 .entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -0700840 int oldVisibility = packageToVisibility.getValue();
841 int currentVisibility =
842 resolveAccountVisibility(account, packageName, accounts);
843 if (isVisible(oldVisibility) != isVisible(currentVisibility)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700844 notifyPackage(packageToVisibility.getKey(), accounts);
845 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700846 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700847 for (String packageNameToNotify : accountRemovedReceivers) {
848 sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
849 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700850 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700851 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700852 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800853 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700854 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700855 }
856
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700857 // Update account visibility in cache and database.
858 private boolean updateAccountVisibilityLocked(Account account, String packageName,
859 int newVisibility, UserAccounts accounts) {
860 final long accountId = accounts.accountsDb.findDeAccountId(account);
861 if (accountId < 0) {
862 return false;
863 }
864
865 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
866 try {
867 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
868 newVisibility)) {
869 return false;
870 }
871 } finally {
872 StrictMode.setThreadPolicy(oldPolicy);
873 }
874 Map<String, Integer> accountVisibility =
875 getPackagesAndVisibilityForAccountLocked(account, accounts);
876 accountVisibility.put(packageName, newVisibility);
877 return true;
878 }
879
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700880 @Override
881 public void registerAccountListener(String[] accountTypes, String opPackageName) {
882 int callingUid = Binder.getCallingUid();
883 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700884
885 int userId = UserHandle.getCallingUserId();
886 long identityToken = clearCallingIdentity();
887 try {
888 UserAccounts accounts = getUserAccounts(userId);
889 registerAccountListener(accountTypes, opPackageName, accounts);
890 } finally {
891 restoreCallingIdentity(identityToken);
892 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800893 }
894
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700895 private void registerAccountListener(String[] accountTypes, String opPackageName,
896 UserAccounts accounts) {
897 synchronized (accounts.mReceiversForType) {
898 if (accountTypes == null) {
899 // null for any type
900 accountTypes = new String[] {null};
901 }
902 for (String type : accountTypes) {
903 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
904 if (receivers == null) {
905 receivers = new HashMap<>();
906 accounts.mReceiversForType.put(type, receivers);
907 }
908 Integer cnt = receivers.get(opPackageName);
909 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800910 }
911 }
912 }
913
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700914 @Override
915 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
916 int callingUid = Binder.getCallingUid();
917 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700918 int userId = UserHandle.getCallingUserId();
919 long identityToken = clearCallingIdentity();
920 try {
921 UserAccounts accounts = getUserAccounts(userId);
922 unregisterAccountListener(accountTypes, opPackageName, accounts);
923 } finally {
924 restoreCallingIdentity(identityToken);
925 }
926 }
927
928 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
929 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700930 synchronized (accounts.mReceiversForType) {
931 if (accountTypes == null) {
932 // null for any type
933 accountTypes = new String[] {null};
934 }
935 for (String type : accountTypes) {
936 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
937 if (receivers == null || receivers.get(opPackageName) == null) {
938 throw new IllegalArgumentException("attempt to unregister wrong receiver");
939 }
940 Integer cnt = receivers.get(opPackageName);
941 if (cnt == 1) {
942 receivers.remove(opPackageName);
943 } else {
944 receivers.put(opPackageName, cnt - 1);
945 }
946 }
947 }
948 }
949
950 // Send notification to all packages which can potentially see the account
951 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
952 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700953
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700954 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700955 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
956 && (packageToVisibility.getValue()
957 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700958 notifyPackage(packageToVisibility.getKey(), accounts);
959 }
960 }
961 }
962
963 /**
964 * Sends a direct intent to a package, notifying it of account visibility change.
965 *
966 * @param packageName to send Account to
967 * @param accounts UserAccount that currently hosts the account
968 */
969 private void notifyPackage(String packageName, UserAccounts accounts) {
970 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
971 intent.setPackage(packageName);
972 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
973 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
974 }
975
976 // Returns a map from package name to visibility, for packages subscribed
977 // to notifications about any account type, or type of provided account
978 // account type or all types.
979 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
980 Set<String> packages = new HashSet<>();
981 synchronized (accounts.mReceiversForType) {
982 for (String type : new String[] {account.type, null}) {
983 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
984 if (receivers != null) {
985 packages.addAll(receivers.keySet());
986 }
987 }
988 }
989 Map<String, Integer> result = new HashMap<>();
990 for (String packageName : packages) {
991 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
992 }
993 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800994 }
995
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700996 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
997 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
998 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
999 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1000 List<ResolveInfo> receivers =
1001 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1002 List<String> result = new ArrayList<>();
1003 if (receivers == null) {
1004 return result;
1005 }
1006 for (ResolveInfo resolveInfo: receivers) {
1007 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
1008 int visibility = resolveAccountVisibility(account, packageName, accounts);
1009 if (visibility == AccountManager.VISIBILITY_VISIBLE
1010 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1011 result.add(packageName);
1012 }
1013 }
1014 return result;
1015 }
1016
1017 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
1018 private boolean shouldNotifyPackageOnAccountRemoval(Account account,
1019 String packageName, UserAccounts accounts) {
1020 int visibility = resolveAccountVisibility(account, packageName, accounts);
1021 if (visibility != AccountManager.VISIBILITY_VISIBLE
1022 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1023 return false;
1024 }
1025
1026 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1027 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1028 intent.setPackage(packageName);
1029 List<ResolveInfo> receivers =
1030 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1031 return (receivers != null && receivers.size() > 0);
1032 }
1033
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001034 private boolean packageExistsForUser(String packageName, int userId) {
1035 try {
1036 long identityToken = clearCallingIdentity();
1037 try {
1038 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -07001039 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001040 } finally {
1041 restoreCallingIdentity(identityToken);
1042 }
1043 } catch (NameNotFoundException e) {
1044 return false;
1045 }
1046 }
1047
1048 /**
1049 * Returns true if packageName is one of special values.
1050 */
1051 private boolean isSpecialPackageKey(String packageName) {
1052 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1053 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1054 }
1055
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001056 private void sendAccountsChangedBroadcast(int userId) {
1057 Log.i(TAG, "the accounts changed, sending broadcast of "
1058 + ACCOUNTS_CHANGED_INTENT.getAction());
1059 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001060 }
1061
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001062 private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001063 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1064 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001065 intent.setPackage(packageName);
1066 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1067 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001068 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1069 }
1070
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001071 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -07001072 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1073 throws RemoteException {
1074 try {
1075 return super.onTransact(code, data, reply, flags);
1076 } catch (RuntimeException e) {
1077 // The account manager only throws security exceptions, so let's
1078 // log all others.
1079 if (!(e instanceof SecurityException)) {
1080 Slog.wtf(TAG, "Account Manager Crash", e);
1081 }
1082 throw e;
1083 }
1084 }
1085
Amith Yamasani258848d2012-08-10 17:06:33 -07001086 private UserManager getUserManager() {
1087 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -07001088 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -07001089 }
1090 return mUserManager;
1091 }
1092
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001093 /**
1094 * Validate internal set of accounts against installed authenticators for
1095 * given user. Clears cached authenticators before validating.
1096 */
1097 public void validateAccounts(int userId) {
1098 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001099 // Invalidate user-specific cache to make sure we catch any
1100 // removed authenticators.
1101 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1102 }
1103
1104 /**
1105 * Validate internal set of accounts against installed authenticators for
1106 * given user. Clear cached authenticators before validating when requested.
1107 */
1108 private void validateAccountsInternal(
1109 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001110 if (Log.isLoggable(TAG, Log.DEBUG)) {
1111 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001112 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001113 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001114 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001115
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001116 if (invalidateAuthenticatorCache) {
1117 mAuthenticatorCache.invalidateCache(accounts.userId);
1118 }
1119
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001120 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1121 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001122 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001123
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001124 synchronized (accounts.dbLock) {
1125 synchronized (accounts.cacheLock) {
1126 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001127
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001128 // Get a map of stored authenticator types to UID
1129 final AccountsDb accountsDb = accounts.accountsDb;
1130 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1131 // Create a list of authenticator type whose previous uid no longer exists
1132 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1133 SparseBooleanArray knownUids = null;
1134 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1135 String type = authToUidEntry.getKey();
1136 int uid = authToUidEntry.getValue();
1137 Integer knownUid = knownAuth.get(type);
1138 if (knownUid != null && uid == knownUid) {
1139 // Remove it from the knownAuth list if it's unchanged.
1140 knownAuth.remove(type);
1141 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001142 /*
1143 * The authenticator is presently not cached and should only be triggered
1144 * when we think an authenticator has been removed (or is being updated).
1145 * But we still want to check if any data with the associated uid is
1146 * around. This is an (imperfect) signal that the package may be updating.
1147 *
1148 * A side effect of this is that an authenticator sharing a uid with
1149 * multiple apps won't get its credentials wiped as long as some app with
1150 * that uid is still on the device. But I suspect that this is a rare case.
1151 * And it isn't clear to me how an attacker could really exploit that
1152 * feature.
1153 *
1154 * The upshot is that we don't have to worry about accounts getting
1155 * uninstalled while the authenticator's package is being updated.
1156 *
1157 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001158 if (knownUids == null) {
1159 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1160 }
1161 if (!knownUids.get(uid)) {
1162 // The authenticator is not presently available to the cache. And the
1163 // package no longer has a data directory (so we surmise it isn't
1164 // updating). So purge its data from the account databases.
1165 obsoleteAuthType.add(type);
1166 // And delete it from the TABLE_META
1167 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1168 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001169 }
1170 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001171
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001172 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1173 // been re-enabled (after being updated for example), then we just overwrite the old
1174 // values.
1175 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1176 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1177 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001178
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001179 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1180 try {
1181 accounts.accountCache.clear();
1182 final HashMap<String, ArrayList<String>> accountNamesByType
1183 = new LinkedHashMap<>();
1184 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1185 final long accountId = accountEntry.getKey();
1186 final Account account = accountEntry.getValue();
1187 if (obsoleteAuthType.contains(account.type)) {
Hui Yu139c2482018-08-10 15:37:51 -07001188 Slog.w(TAG, "deleting account " + account.toSafeString()
1189 + " because type " + account.type
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001190 + "'s registered authenticator no longer exist.");
1191 Map<String, Integer> packagesToVisibility =
1192 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001193 List<String> accountRemovedReceivers =
1194 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001195 accountsDb.beginTransaction();
1196 try {
1197 accountsDb.deleteDeAccount(accountId);
1198 // Also delete from CE table if user is unlocked; if user is
1199 // currently locked the account will be removed later by
1200 // syncDeCeAccountsLocked
1201 if (userUnlocked) {
1202 accountsDb.deleteCeAccount(accountId);
1203 }
1204 accountsDb.setTransactionSuccessful();
1205 } finally {
1206 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001207 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001208 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001209
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001210 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1211 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001212
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001213 accounts.userDataCache.remove(account);
1214 accounts.authTokenCache.remove(account);
1215 accounts.accountTokenCaches.remove(account);
1216 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001217
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001218 for (Entry<String, Integer> packageToVisibility :
1219 packagesToVisibility.entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -07001220 if (isVisible(packageToVisibility.getValue())) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001221 notifyPackage(packageToVisibility.getKey(), accounts);
1222 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001223 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001224 for (String packageName : accountRemovedReceivers) {
1225 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1226 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001227 } else {
1228 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1229 if (accountNames == null) {
1230 accountNames = new ArrayList<>();
1231 accountNamesByType.put(account.type, accountNames);
1232 }
1233 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001234 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001235 }
1236 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1237 final String accountType = cur.getKey();
1238 final ArrayList<String> accountNames = cur.getValue();
1239 final Account[] accountsForType = new Account[accountNames.size()];
1240 for (int i = 0; i < accountsForType.length; i++) {
1241 accountsForType[i] = new Account(accountNames.get(i), accountType,
1242 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001243 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001244 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001245 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001246 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1247 } finally {
1248 if (accountDeleted) {
1249 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001250 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001251 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001252 }
1253 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001254 }
1255
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001256 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1257 // Get the UIDs of all apps that might have data on the device. We want
1258 // to preserve user data if the app might otherwise be storing data.
1259 List<PackageInfo> pkgsWithData =
1260 mPackageManager.getInstalledPackagesAsUser(
1261 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1262 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1263 for (PackageInfo pkgInfo : pkgsWithData) {
1264 if (pkgInfo.applicationInfo != null
1265 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1266 knownUids.put(pkgInfo.applicationInfo.uid, true);
1267 }
1268 }
1269 return knownUids;
1270 }
1271
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001272 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001273 Context context,
1274 int userId) {
1275 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001276 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1277 }
1278
1279 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1280 IAccountAuthenticatorCache authCache,
1281 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001282 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001283 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1284 .getAllServices(userId)) {
1285 knownAuth.put(service.type.type, service.uid);
1286 }
1287 return knownAuth;
1288 }
1289
Amith Yamasani04e0d262012-02-14 11:50:53 -08001290 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001291 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001292 }
1293
1294 protected UserAccounts getUserAccounts(int userId) {
1295 synchronized (mUsers) {
1296 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001297 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001298 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001299 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1300 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001301 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001302 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001303 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001304 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001305 validateAccounts = true;
1306 }
1307 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001308 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001309 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001310 synchronized (accounts.dbLock) {
1311 synchronized (accounts.cacheLock) {
1312 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1313 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1314 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001315 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001316 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001317 }
1318 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001319 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001320 }
1321 return accounts;
1322 }
1323 }
1324
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001325 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1326 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001327 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001328 if (!accountsToRemove.isEmpty()) {
Hui Yu139c2482018-08-10 15:37:51 -07001329 Slog.i(TAG, accountsToRemove.size()
1330 + " accounts were previously deleted while user "
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001331 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001332 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1333 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001334
1335 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001336 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001337 }
1338 }
1339 }
1340
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001341 private void purgeOldGrantsAll() {
1342 synchronized (mUsers) {
1343 for (int i = 0; i < mUsers.size(); i++) {
1344 purgeOldGrants(mUsers.valueAt(i));
1345 }
1346 }
1347 }
1348
1349 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001350 synchronized (accounts.dbLock) {
1351 synchronized (accounts.cacheLock) {
1352 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1353 for (int uid : uids) {
1354 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1355 if (packageExists) {
1356 continue;
1357 }
1358 Log.d(TAG, "deleting grants for UID " + uid
1359 + " because its package is no longer installed");
1360 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001361 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001362 }
1363 }
1364 }
1365
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001366 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001367 if (isSpecialPackageKey(packageName)) {
1368 return;
1369 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001370 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001371 int numberOfUsers = mUsers.size();
1372 for (int i = 0; i < numberOfUsers; i++) {
1373 UserAccounts accounts = mUsers.valueAt(i);
1374 try {
1375 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1376 } catch (NameNotFoundException e) {
1377 // package does not exist - remove visibility values
1378 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001379 synchronized (accounts.dbLock) {
1380 synchronized (accounts.cacheLock) {
1381 for (Account account : accounts.visibilityCache.keySet()) {
1382 Map<String, Integer> accountVisibility =
1383 getPackagesAndVisibilityForAccountLocked(account, accounts);
1384 accountVisibility.remove(packageName);
1385 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001386 }
1387 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001388 }
1389 }
1390 }
1391 }
1392
Fyodor Kupolov945c97e2017-06-21 17:45:19 -07001393 private void purgeUserData(int userId) {
Amith Yamasani13593602012-03-22 16:16:17 -07001394 UserAccounts accounts;
1395 synchronized (mUsers) {
1396 accounts = mUsers.get(userId);
1397 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001398 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001399 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001400 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001401 synchronized (accounts.dbLock) {
1402 synchronized (accounts.cacheLock) {
Fyodor Kupolov56e158f2017-05-23 16:41:51 -07001403 accounts.statementForLogging.close();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001404 accounts.accountsDb.close();
1405 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001406 }
Amith Yamasani13593602012-03-22 16:16:17 -07001407 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001408 }
1409
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001410 @VisibleForTesting
1411 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001412 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1413 }
1414
1415 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001416 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1417 Log.v(TAG, "onUserUnlocked " + userId);
1418 }
1419 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001420 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001421 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001422 if (userId < 1) return;
Fyodor Kupolov2bc895d2017-12-19 11:53:47 -08001423 mHandler.post(() -> syncSharedAccounts(userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001424 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001425
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001426 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001427 // Check if there's a shared account that needs to be created as an account
1428 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1429 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001430 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001431 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001432 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001433 : UserHandle.USER_SYSTEM;
1434 if (parentUserId < 0) {
1435 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1436 return;
1437 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001438 for (Account sa : sharedAccounts) {
1439 if (ArrayUtils.contains(accounts, sa)) continue;
1440 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001441 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001442 }
1443 }
1444
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001445 @Override
1446 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001447 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001448 }
1449
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001450 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001451 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001452 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001453 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1454 Log.v(TAG, "getPassword: " + account
1455 + ", caller's uid " + Binder.getCallingUid()
1456 + ", pid " + Binder.getCallingPid());
1457 }
Fred Quintana382601f2010-03-25 12:25:10 -07001458 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001459 int userId = UserHandle.getCallingUserId();
1460 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001461 String msg = String.format(
1462 "uid %s cannot get secrets for accounts of type: %s",
1463 callingUid,
1464 account.type);
1465 throw new SecurityException(msg);
1466 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001467 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001468 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001469 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001470 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001471 } finally {
1472 restoreCallingIdentity(identityToken);
1473 }
1474 }
1475
Amith Yamasani04e0d262012-02-14 11:50:53 -08001476 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001477 if (account == null) {
1478 return null;
1479 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001480 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001481 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1482 return null;
1483 }
Fred Quintana31957f12009-10-21 13:43:10 -07001484
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001485 synchronized (accounts.dbLock) {
1486 synchronized (accounts.cacheLock) {
1487 return accounts.accountsDb
1488 .findAccountPasswordByNameAndType(account.name, account.type);
1489 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001490 }
1491 }
1492
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001493 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001494 public String getPreviousName(Account account) {
1495 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1496 Log.v(TAG, "getPreviousName: " + account
1497 + ", caller's uid " + Binder.getCallingUid()
1498 + ", pid " + Binder.getCallingPid());
1499 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001500 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001501 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001502 long identityToken = clearCallingIdentity();
1503 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001504 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001505 return readPreviousNameInternal(accounts, account);
1506 } finally {
1507 restoreCallingIdentity(identityToken);
1508 }
1509 }
1510
1511 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1512 if (account == null) {
1513 return null;
1514 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001515 synchronized (accounts.dbLock) {
1516 synchronized (accounts.cacheLock) {
1517 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1518 if (previousNameRef == null) {
1519 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1520 previousNameRef = new AtomicReference<>(previousName);
1521 accounts.previousNameCache.put(account, previousNameRef);
1522 return previousName;
1523 } else {
1524 return previousNameRef.get();
1525 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001526 }
1527 }
1528 }
1529
1530 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001531 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001532 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001533 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001534 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1535 account, key, callingUid, Binder.getCallingPid());
1536 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001537 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001538 Preconditions.checkNotNull(account, "account cannot be null");
1539 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001540 int userId = UserHandle.getCallingUserId();
1541 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001542 String msg = String.format(
1543 "uid %s cannot get user data for accounts of type: %s",
1544 callingUid,
1545 account.type);
1546 throw new SecurityException(msg);
1547 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001548 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001549 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1550 return null;
1551 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001552 long identityToken = clearCallingIdentity();
1553 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001554 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001555 if (!accountExistsCache(accounts, account)) {
1556 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001557 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001558 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001559 } finally {
1560 restoreCallingIdentity(identityToken);
1561 }
1562 }
1563
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001564 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001565 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001566 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001567 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1568 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001569 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001570 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001571 + ", pid " + Binder.getCallingPid());
1572 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001573 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001574 if (isCrossUser(callingUid, userId)) {
1575 throw new SecurityException(
1576 String.format(
1577 "User %s tying to get authenticator types for %s" ,
1578 UserHandle.getCallingUserId(),
1579 userId));
1580 }
1581
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001582 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001583 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001584 return getAuthenticatorTypesInternal(userId);
1585
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001586 } finally {
1587 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001588 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001589 }
1590
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001591 /**
1592 * Should only be called inside of a clearCallingIdentity block.
1593 */
1594 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001595 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001596 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1597 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1598 AuthenticatorDescription[] types =
1599 new AuthenticatorDescription[authenticatorCollection.size()];
1600 int i = 0;
1601 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1602 : authenticatorCollection) {
1603 types[i] = authenticator.type;
1604 i++;
1605 }
1606 return types;
1607 }
1608
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001609 private boolean isCrossUser(int callingUid, int userId) {
1610 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001611 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001612 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001613 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1614 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001615 }
1616
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001617 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001618 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001619 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001620 }
1621
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001622 @Override
1623 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001624 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001625 int callingUid = Binder.getCallingUid();
1626 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1627 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001628 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001629 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001630 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1631 final UserAccounts toAccounts = getUserAccounts(userTo);
1632 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001633 if (response != null) {
1634 Bundle result = new Bundle();
1635 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1636 try {
1637 response.onResult(result);
1638 } catch (RemoteException e) {
1639 Slog.w(TAG, "Failed to report error back to the client." + e);
1640 }
1641 }
1642 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001643 }
1644
Hui Yu139c2482018-08-10 15:37:51 -07001645 Slog.d(TAG, "Copying account " + account.toSafeString()
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001646 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001647 long identityToken = clearCallingIdentity();
1648 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001649 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001650 false /* stripAuthTokenFromResult */, account.name,
1651 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001652 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001653 protected String toDebugString(long now) {
1654 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1655 + ", " + account.type;
1656 }
1657
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001658 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001659 public void run() throws RemoteException {
1660 mAuthenticator.getAccountCredentialsForCloning(this, account);
1661 }
1662
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001663 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001664 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001665 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001666 if (result != null
1667 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1668 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001669 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001670 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001671 super.onResult(result);
1672 }
1673 }
1674 }.bind();
1675 } finally {
1676 restoreCallingIdentity(identityToken);
1677 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001678 }
1679
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001680 @Override
1681 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001682 final int callingUid = Binder.getCallingUid();
1683 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1684 String msg = String.format(
1685 "accountAuthenticated( account: %s, callerUid: %s)",
1686 account,
1687 callingUid);
1688 Log.v(TAG, msg);
1689 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001690 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001691 int userId = UserHandle.getCallingUserId();
1692 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001693 String msg = String.format(
1694 "uid %s cannot notify authentication for accounts of type: %s",
1695 callingUid,
1696 account.type);
1697 throw new SecurityException(msg);
1698 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001699
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001700 if (!canUserModifyAccounts(userId, callingUid) ||
1701 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001702 return false;
1703 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001704
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001705 long identityToken = clearCallingIdentity();
1706 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001707 UserAccounts accounts = getUserAccounts(userId);
1708 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001709 } finally {
1710 restoreCallingIdentity(identityToken);
1711 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001712 }
1713
1714 private boolean updateLastAuthenticatedTime(Account account) {
1715 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001716 synchronized (accounts.dbLock) {
1717 synchronized (accounts.cacheLock) {
1718 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1719 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001720 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001721 }
1722
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001723 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001724 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1725 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001726 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001727 long id = clearCallingIdentity();
1728 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001729 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001730 false /* stripAuthTokenFromResult */, account.name,
1731 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001732 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001733 protected String toDebugString(long now) {
1734 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1735 + ", " + account.type;
1736 }
1737
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001738 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001739 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001740 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001741 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1742 if (acc.equals(account)) {
1743 mAuthenticator.addAccountFromCredentials(
1744 this, account, accountCredentials);
1745 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001746 }
1747 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001748 }
1749
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001750 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001751 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001752 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001753 // TODO: Anything to do if if succedded?
1754 // TODO: If it failed: Show error notification? Should we remove the shadow
1755 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001756 // TODO: what we do with the visibility?
1757
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001758 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001759 }
1760
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001761 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001762 public void onError(int errorCode, String errorMessage) {
1763 super.onError(errorCode, errorMessage);
1764 // TODO: Show error notification to user
1765 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1766 }
1767
1768 }.bind();
1769 } finally {
1770 restoreCallingIdentity(id);
1771 }
1772 }
1773
Amith Yamasani04e0d262012-02-14 11:50:53 -08001774 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001775 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001776 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001777 if (account == null) {
1778 return false;
1779 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001780 if (!isLocalUnlockedUser(accounts.userId)) {
Hui Yu139c2482018-08-10 15:37:51 -07001781 Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
1782 + accounts.userId + " is locked. callingUid=" + callingUid);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001783 return false;
1784 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001785 synchronized (accounts.dbLock) {
1786 synchronized (accounts.cacheLock) {
1787 accounts.accountsDb.beginTransaction();
1788 try {
1789 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001790 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001791 + ", skipping since the account already exists");
1792 return false;
1793 }
1794 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1795 if (accountId < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001796 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001797 + ", skipping the DB insert failed");
1798 return false;
1799 }
1800 // Insert into DE table
1801 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001802 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001803 + ", skipping the DB insert failed");
1804 return false;
1805 }
1806 if (extras != null) {
1807 for (String key : extras.keySet()) {
1808 final String value = extras.getString(key);
1809 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001810 Log.w(TAG, "insertAccountIntoDatabase: "
1811 + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001812 + ", skipping since insertExtra failed for key " + key);
1813 return false;
1814 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001815 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001816 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001817
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001818 if (packageToVisibility != null) {
1819 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1820 setAccountVisibility(account, entry.getKey() /* package */,
1821 entry.getValue() /* visibility */, false /* notify */,
1822 accounts);
1823 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001824 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001825 accounts.accountsDb.setTransactionSuccessful();
1826
1827 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1828 accountId,
1829 accounts, callingUid);
1830
1831 insertAccountIntoCacheLocked(accounts, account);
1832 } finally {
1833 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001834 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001835 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001836 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001837 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1838 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001839 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001840
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001841 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001842 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1843 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001844
Amith Yamasani5be347b2013-03-31 17:44:31 -07001845 return true;
1846 }
1847
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001848 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001849 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001850 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001851 }
1852 }
1853
Amith Yamasani5be347b2013-03-31 17:44:31 -07001854 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001855 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001856 * running, then clone the account too.
1857 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001858 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001859 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001860 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001861 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001862 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001863 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001864 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001865 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001866 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001867 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001868 }
1869 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001870 }
1871 }
1872
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001873 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001874 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001875 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001876 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001877 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001878 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1879 Log.v(TAG, "hasFeatures: " + account
1880 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001881 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001882 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001883 + ", pid " + Binder.getCallingPid());
1884 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001885 Preconditions.checkArgument(account != null, "account cannot be null");
1886 Preconditions.checkArgument(response != null, "response cannot be null");
1887 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001888 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001889 checkReadAccountsPermitted(callingUid, account.type, userId,
1890 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001891
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001892 long identityToken = clearCallingIdentity();
1893 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001894 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001895 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001896 } finally {
1897 restoreCallingIdentity(identityToken);
1898 }
1899 }
1900
1901 private class TestFeaturesSession extends Session {
1902 private final String[] mFeatures;
1903 private final Account mAccount;
1904
Amith Yamasani04e0d262012-02-14 11:50:53 -08001905 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001906 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001907 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001908 true /* stripAuthTokenFromResult */, account.name,
1909 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001910 mFeatures = features;
1911 mAccount = account;
1912 }
1913
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001914 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001915 public void run() throws RemoteException {
1916 try {
1917 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1918 } catch (RemoteException e) {
1919 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1920 }
1921 }
1922
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001923 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001924 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001925 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001926 IAccountManagerResponse response = getResponseAndClose();
1927 if (response != null) {
1928 try {
1929 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001930 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001931 return;
1932 }
Fred Quintana56285a62010-12-02 14:20:51 -08001933 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1934 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1935 + response);
1936 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001937 final Bundle newResult = new Bundle();
1938 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1939 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1940 response.onResult(newResult);
1941 } catch (RemoteException e) {
1942 // if the caller is dead then there is no one to care about remote exceptions
1943 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1944 Log.v(TAG, "failure while notifying response", e);
1945 }
1946 }
1947 }
1948 }
1949
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001950 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001951 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001952 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001953 + ", " + mAccount
1954 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1955 }
1956 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001957
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001958 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001959 public void renameAccount(
1960 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001961 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001962 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1963 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001964 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001965 + ", pid " + Binder.getCallingPid());
1966 }
1967 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001968 int userId = UserHandle.getCallingUserId();
1969 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001970 String msg = String.format(
1971 "uid %s cannot rename accounts of type: %s",
1972 callingUid,
1973 accountToRename.type);
1974 throw new SecurityException(msg);
1975 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001976 long identityToken = clearCallingIdentity();
1977 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001978 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001979 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001980 Bundle result = new Bundle();
1981 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1982 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001983 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1984 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001985 try {
1986 response.onResult(result);
1987 } catch (RemoteException e) {
1988 Log.w(TAG, e.getMessage());
1989 }
1990 } finally {
1991 restoreCallingIdentity(identityToken);
1992 }
1993 }
1994
1995 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001996 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001997 Account resultAccount = null;
1998 /*
1999 * Cancel existing notifications. Let authenticators
2000 * re-post notifications as required. But we don't know if
2001 * the authenticators have bound their notifications to
2002 * now stale account name data.
2003 *
2004 * With a rename api, we might not need to do this anymore but it
2005 * shouldn't hurt.
2006 */
2007 cancelNotification(
2008 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04002009 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002010 synchronized(accounts.credentialsPermissionNotificationIds) {
2011 for (Pair<Pair<Account, String>, Integer> pair:
2012 accounts.credentialsPermissionNotificationIds.keySet()) {
2013 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002014 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002015 cancelNotification(id, new UserHandle(accounts.userId));
2016 }
2017 }
2018 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002019 synchronized (accounts.dbLock) {
2020 synchronized (accounts.cacheLock) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002021 List<String> accountRemovedReceivers =
2022 getAccountRemovedReceivers(accountToRename, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002023 accounts.accountsDb.beginTransaction();
2024 Account renamedAccount = new Account(newName, accountToRename.type);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002025 try {
chengangf2d081c2017-12-27 17:17:32 +08002026 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
2027 Log.e(TAG, "renameAccount failed - account with new name already exists");
2028 return null;
2029 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002030 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2031 if (accountId >= 0) {
2032 accounts.accountsDb.renameCeAccount(accountId, newName);
2033 if (accounts.accountsDb.renameDeAccount(
2034 accountId, newName, accountToRename.name)) {
2035 accounts.accountsDb.setTransactionSuccessful();
2036 } else {
2037 Log.e(TAG, "renameAccount failed");
2038 return null;
2039 }
2040 } else {
2041 Log.e(TAG, "renameAccount failed - old account does not exist");
2042 return null;
2043 }
2044 } finally {
2045 accounts.accountsDb.endTransaction();
2046 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002047 /*
2048 * Database transaction was successful. Clean up cached
2049 * data associated with the account in the user profile.
2050 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002051 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002052 /*
2053 * Extract the data and token caches before removing the
2054 * old account to preserve the user data associated with
2055 * the account.
2056 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002057 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2058 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2059 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2060 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002061 /*
2062 * Update the cached data associated with the renamed
2063 * account.
2064 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002065 accounts.userDataCache.put(renamedAccount, tmpData);
2066 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2067 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2068 accounts.previousNameCache.put(
2069 renamedAccount,
2070 new AtomicReference<>(accountToRename.name));
2071 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002072
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002073 int parentUserId = accounts.userId;
2074 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002075 /*
2076 * Owner or system user account was renamed, rename the account for
2077 * those users with which the account was shared.
2078 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002079 List<UserInfo> users = getUserManager().getUsers(true);
2080 for (UserInfo user : users) {
2081 if (user.isRestricted()
2082 && (user.restrictedProfileParentId == parentUserId)) {
2083 renameSharedAccountAsUser(accountToRename, newName, user.id);
2084 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002085 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002086 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002087
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002088 sendNotificationAccountUpdated(resultAccount, accounts);
2089 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002090 for (String packageName : accountRemovedReceivers) {
2091 sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2092 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002093 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002094 }
2095 return resultAccount;
2096 }
2097
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002098 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002099 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002100 return userInfo != null && userInfo.canHaveProfile();
2101 }
2102
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002103 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002104 public void removeAccount(IAccountManagerResponse response, Account account,
2105 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002106 removeAccountAsUser(
2107 response,
2108 account,
2109 expectActivityLaunch,
2110 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002111 }
2112
2113 @Override
2114 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002115 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002116 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002117 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2118 Log.v(TAG, "removeAccount: " + account
2119 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002120 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002121 + ", pid " + Binder.getCallingPid()
2122 + ", for user id " + userId);
2123 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002124 Preconditions.checkArgument(account != null, "account cannot be null");
2125 Preconditions.checkArgument(response != null, "response cannot be null");
2126
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002127 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002128 if (isCrossUser(callingUid, userId)) {
2129 throw new SecurityException(
2130 String.format(
2131 "User %s tying remove account for %s" ,
2132 UserHandle.getCallingUserId(),
2133 userId));
2134 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002135 /*
Alex Chauf788f9c2017-12-08 15:16:46 +00002136 * Only the system, authenticator or profile owner should be allowed to remove accounts for
2137 * that authenticator. This will let users remove accounts (via Settings in the system) but
2138 * not arbitrary applications (like competing authenticators).
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002139 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002140 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002141 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
Alex Chauf788f9c2017-12-08 15:16:46 +00002142 && !isSystemUid(callingUid)
2143 && !isProfileOwner(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002144 String msg = String.format(
2145 "uid %s cannot remove accounts of type: %s",
2146 callingUid,
2147 account.type);
2148 throw new SecurityException(msg);
2149 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002150 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002151 try {
2152 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2153 "User cannot modify accounts");
2154 } catch (RemoteException re) {
2155 }
2156 return;
2157 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002158 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002159 try {
2160 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2161 "User cannot modify accounts of this type (policy).");
2162 } catch (RemoteException re) {
2163 }
2164 return;
2165 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002166 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002167 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002168 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002169 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002170 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002171 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002172 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002173 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002174 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002175 }
2176 }
2177 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002178 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002179 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002180 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2181 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002182 accountId,
2183 accounts,
2184 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002185 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002186 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2187 } finally {
2188 restoreCallingIdentity(identityToken);
2189 }
2190 }
2191
2192 @Override
2193 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002194 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002195 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2196 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002197 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002198 + ", pid " + Binder.getCallingPid());
2199 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002200 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002201 if (account == null) {
2202 /*
2203 * Null accounts should result in returning false, as per
2204 * AccountManage.addAccountExplicitly(...) java doc.
2205 */
2206 Log.e(TAG, "account is null");
2207 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002208 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002209 String msg = String.format(
Brandon Weeks9e4e96d2017-08-24 15:24:16 -07002210 "uid %s cannot explicitly remove accounts of type: %s",
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002211 callingUid,
2212 account.type);
2213 throw new SecurityException(msg);
2214 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002215 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002216 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002217 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002218 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2219 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002220 accountId,
2221 accounts,
2222 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002223 long identityToken = clearCallingIdentity();
2224 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002225 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002226 } finally {
2227 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002228 }
Fred Quintana60307342009-03-24 22:48:12 -07002229 }
2230
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002231 private class RemoveAccountSession extends Session {
2232 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002233 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002234 Account account, boolean expectActivityLaunch) {
2235 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002236 true /* stripAuthTokenFromResult */, account.name,
2237 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002238 mAccount = account;
2239 }
2240
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002241 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002242 protected String toDebugString(long now) {
2243 return super.toDebugString(now) + ", removeAccount"
2244 + ", account " + mAccount;
2245 }
2246
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002247 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002248 public void run() throws RemoteException {
2249 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2250 }
2251
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002252 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002253 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002254 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002255 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2256 && !result.containsKey(AccountManager.KEY_INTENT)) {
2257 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002258 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002259 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002260 }
2261 IAccountManagerResponse response = getResponseAndClose();
2262 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002263 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2264 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2265 + response);
2266 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002267 try {
tiansiming5330b5a2017-10-13 10:57:25 +08002268 response.onResult(result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002269 } catch (RemoteException e) {
tiansiming5330b5a2017-10-13 10:57:25 +08002270 Slog.e(TAG, "Error calling onResult()", e);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002271 }
2272 }
2273 }
2274 super.onResult(result);
2275 }
2276 }
2277
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002278 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002279 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002280 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002281 }
2282
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002283 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002284 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002285 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002286 if (!userUnlocked) {
Hui Yu139c2482018-08-10 15:37:51 -07002287 Slog.i(TAG, "Removing account " + account.toSafeString()
2288 + " while user " + accounts.userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002289 + " is still locked. CE data will be removed later");
2290 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002291 synchronized (accounts.dbLock) {
2292 synchronized (accounts.cacheLock) {
2293 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2294 accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002295 List<String> accountRemovedReceivers =
2296 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002297 accounts.accountsDb.beginTransaction();
2298 // Set to a dummy value, this will only be used if the database
2299 // transaction succeeds.
2300 long accountId = -1;
2301 try {
2302 accountId = accounts.accountsDb.findDeAccountId(account);
2303 if (accountId >= 0) {
2304 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002305 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002306 // always delete from CE table if CE storage is available
2307 // DE account could be removed while CE was locked
2308 if (userUnlocked) {
2309 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2310 if (ceAccountId >= 0) {
2311 accounts.accountsDb.deleteCeAccount(ceAccountId);
2312 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002313 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002314 accounts.accountsDb.setTransactionSuccessful();
2315 } finally {
2316 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002317 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002318 if (isChanged) {
2319 removeAccountFromCacheLocked(accounts, account);
2320 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2321 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002322 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2323 || (packageToVisibility.getValue()
2324 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002325 notifyPackage(packageToVisibility.getKey(), accounts);
2326 }
2327 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002328
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002329 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2330 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002331 for (String packageName : accountRemovedReceivers) {
2332 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2333 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002334 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2335 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2336 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2337 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002338 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002339 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002340 long id = Binder.clearCallingIdentity();
2341 try {
2342 int parentUserId = accounts.userId;
2343 if (canHaveProfile(parentUserId)) {
2344 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002345 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002346 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002347 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002348 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002349 }
2350 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002351 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002352 } finally {
2353 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002354 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002355
2356 if (isChanged) {
2357 synchronized (accounts.credentialsPermissionNotificationIds) {
2358 for (Pair<Pair<Account, String>, Integer> key
2359 : accounts.credentialsPermissionNotificationIds.keySet()) {
2360 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002361 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002362 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002363 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002364 account, uid, false));
2365 }
2366 }
2367 }
2368 }
2369
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002370 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002371 }
2372
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002373 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002374 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002375 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002376 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2377 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002378 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2379 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002380 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002381 + ", pid " + Binder.getCallingPid());
2382 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002383 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002384 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002385 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002386 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002387 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002388 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002389 accounts.accountsDb.beginTransaction();
2390 try {
2391 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2392 accounts.accountsDb.setTransactionSuccessful();
2393 } finally {
2394 accounts.accountsDb.endTransaction();
2395 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002396 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002397 for (Pair<Account, String> tokenInfo : deletedTokens) {
2398 Account act = tokenInfo.first;
2399 String tokenType = tokenInfo.second;
2400 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002401 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002402 // wipe out cached token in memory.
2403 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002404 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002405 }
Fred Quintana60307342009-03-24 22:48:12 -07002406 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002407 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002408 }
2409 }
2410
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002411 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002412 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002413 // TODO Move to AccountsDB
2414 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002415 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002416
Fred Quintana33269202009-04-20 16:05:10 -07002417 try {
2418 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002419 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002420 String accountName = cursor.getString(1);
2421 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002422 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002423 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002424 }
Fred Quintana33269202009-04-20 16:05:10 -07002425 } finally {
2426 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002427 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002428 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002429 }
2430
Carlos Valdivia91979be2015-05-22 14:11:35 -07002431 private void saveCachedToken(
2432 UserAccounts accounts,
2433 Account account,
2434 String callerPkg,
2435 byte[] callerSigDigest,
2436 String tokenType,
2437 String token,
2438 long expiryMillis) {
2439
2440 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2441 return;
2442 }
2443 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002444 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002445 synchronized (accounts.cacheLock) {
2446 accounts.accountTokenCaches.put(
2447 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002448 }
2449 }
2450
Amith Yamasani04e0d262012-02-14 11:50:53 -08002451 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2452 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002453 if (account == null || type == null) {
2454 return false;
2455 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002456 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002457 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002458 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002459 accounts.accountsDb.beginTransaction();
2460 boolean updateCache = false;
2461 try {
2462 long accountId = accounts.accountsDb.findDeAccountId(account);
2463 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002464 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002465 }
2466 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2467 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2468 accounts.accountsDb.setTransactionSuccessful();
2469 updateCache = true;
2470 return true;
2471 }
2472 return false;
2473 } finally {
2474 accounts.accountsDb.endTransaction();
2475 if (updateCache) {
2476 synchronized (accounts.cacheLock) {
2477 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2478 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002479 }
Fred Quintana33269202009-04-20 16:05:10 -07002480 }
Fred Quintana60307342009-03-24 22:48:12 -07002481 }
2482 }
2483
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002484 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002485 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002486 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002487 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2488 Log.v(TAG, "peekAuthToken: " + account
2489 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002490 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002491 + ", pid " + Binder.getCallingPid());
2492 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002493 Preconditions.checkNotNull(account, "account cannot be null");
2494 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002495 int userId = UserHandle.getCallingUserId();
2496 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002497 String msg = String.format(
2498 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2499 callingUid,
2500 account.type);
2501 throw new SecurityException(msg);
2502 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002503 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002504 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2505 + callingUid);
2506 return null;
2507 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002508 long identityToken = clearCallingIdentity();
2509 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002510 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002511 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002512 } finally {
2513 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002514 }
Fred Quintana60307342009-03-24 22:48:12 -07002515 }
2516
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002517 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002518 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002519 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002520 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2521 Log.v(TAG, "setAuthToken: " + account
2522 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002523 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002524 + ", pid " + Binder.getCallingPid());
2525 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002526 Preconditions.checkNotNull(account, "account cannot be null");
2527 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002528 int userId = UserHandle.getCallingUserId();
2529 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002530 String msg = String.format(
2531 "uid %s cannot set auth tokens associated with accounts of type: %s",
2532 callingUid,
2533 account.type);
2534 throw new SecurityException(msg);
2535 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002536 long identityToken = clearCallingIdentity();
2537 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002538 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002539 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002540 } finally {
2541 restoreCallingIdentity(identityToken);
2542 }
Fred Quintana60307342009-03-24 22:48:12 -07002543 }
2544
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002545 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002546 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002547 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002548 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2549 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002550 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002551 + ", pid " + Binder.getCallingPid());
2552 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002553 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002554 int userId = UserHandle.getCallingUserId();
2555 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002556 String msg = String.format(
2557 "uid %s cannot set secrets for accounts of type: %s",
2558 callingUid,
2559 account.type);
2560 throw new SecurityException(msg);
2561 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002562 long identityToken = clearCallingIdentity();
2563 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002564 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002565 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002566 } finally {
2567 restoreCallingIdentity(identityToken);
2568 }
Fred Quintana60307342009-03-24 22:48:12 -07002569 }
2570
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002571 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2572 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002573 if (account == null) {
2574 return;
2575 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002576 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002577 synchronized (accounts.dbLock) {
2578 synchronized (accounts.cacheLock) {
2579 accounts.accountsDb.beginTransaction();
2580 try {
2581 final long accountId = accounts.accountsDb.findDeAccountId(account);
2582 if (accountId >= 0) {
2583 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2584 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2585 accounts.authTokenCache.remove(account);
2586 accounts.accountTokenCaches.remove(account);
2587 accounts.accountsDb.setTransactionSuccessful();
2588 // If there is an account whose password will be updated and the database
2589 // transactions succeed, then we say that a change has occured. Even if the
2590 // new password is the same as the old and there were no authtokens to
2591 // delete.
2592 isChanged = true;
2593 String action = (password == null || password.length() == 0) ?
2594 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2595 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2596 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2597 callingUid);
2598 }
2599 } finally {
2600 accounts.accountsDb.endTransaction();
2601 if (isChanged) {
2602 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2603 sendNotificationAccountUpdated(account, accounts);
2604 sendAccountsChangedBroadcast(accounts.userId);
2605 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002606 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002607 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002608 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002609 }
2610
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002611 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002612 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002613 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002614 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2615 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002616 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002617 + ", pid " + Binder.getCallingPid());
2618 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002619 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002620 int userId = UserHandle.getCallingUserId();
2621 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002622 String msg = String.format(
2623 "uid %s cannot clear passwords for accounts of type: %s",
2624 callingUid,
2625 account.type);
2626 throw new SecurityException(msg);
2627 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002628 long identityToken = clearCallingIdentity();
2629 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002630 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002631 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002632 } finally {
2633 restoreCallingIdentity(identityToken);
2634 }
Fred Quintana60307342009-03-24 22:48:12 -07002635 }
2636
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002637 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002638 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002639 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002640 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2641 Log.v(TAG, "setUserData: " + account
2642 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002643 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002644 + ", pid " + Binder.getCallingPid());
2645 }
Fred Quintana382601f2010-03-25 12:25:10 -07002646 if (key == null) throw new IllegalArgumentException("key is null");
2647 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002648 int userId = UserHandle.getCallingUserId();
2649 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002650 String msg = String.format(
2651 "uid %s cannot set user data for accounts of type: %s",
2652 callingUid,
2653 account.type);
2654 throw new SecurityException(msg);
2655 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002656 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002657 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002658 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002659 if (!accountExistsCache(accounts, account)) {
2660 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002661 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002662 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002663 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002664 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002665 }
2666 }
2667
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002668 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2669 synchronized (accounts.cacheLock) {
2670 if (accounts.accountCache.containsKey(account.type)) {
2671 for (Account acc : accounts.accountCache.get(account.type)) {
2672 if (acc.name.equals(account.name)) {
2673 return true;
2674 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002675 }
2676 }
2677 }
2678 return false;
2679 }
2680
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002681 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002682 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002683 synchronized (accounts.dbLock) {
2684 accounts.accountsDb.beginTransaction();
2685 try {
2686 long accountId = accounts.accountsDb.findDeAccountId(account);
2687 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002688 return;
2689 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002690 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2691 if (extrasId < 0) {
2692 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2693 if (extrasId < 0) {
2694 return;
2695 }
2696 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2697 return;
2698 }
2699 accounts.accountsDb.setTransactionSuccessful();
2700 } finally {
2701 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002702 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002703 synchronized (accounts.cacheLock) {
2704 writeUserDataIntoCacheLocked(accounts, account, key, value);
2705 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002706 }
2707 }
2708
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002709 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002710 if (result == null) {
2711 Log.e(TAG, "the result is unexpectedly null", new Exception());
2712 }
2713 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2714 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2715 + response);
2716 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002717 try {
2718 response.onResult(result);
2719 } catch (RemoteException e) {
2720 // if the caller is dead then there is no one to care about remote
2721 // exceptions
2722 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2723 Log.v(TAG, "failure while notifying response", e);
2724 }
2725 }
2726 }
2727
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002728 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002729 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2730 final String authTokenType)
2731 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002732 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2733 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002734
Fred Quintanad9640ec2012-05-23 12:37:00 -07002735 final int callingUid = getCallingUid();
2736 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002737 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002738 throw new SecurityException("can only call from system");
2739 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002740 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002741 long identityToken = clearCallingIdentity();
2742 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002743 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002744 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2745 false /* stripAuthTokenFromResult */, null /* accountName */,
2746 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002747 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002748 protected String toDebugString(long now) {
2749 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002750 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002751 + ", authTokenType " + authTokenType;
2752 }
2753
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002754 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002755 public void run() throws RemoteException {
2756 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2757 }
2758
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002759 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002760 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002761 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002762 if (result != null) {
2763 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2764 Bundle bundle = new Bundle();
2765 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2766 super.onResult(bundle);
2767 return;
2768 } else {
2769 super.onResult(result);
2770 }
2771 }
2772 }.bind();
2773 } finally {
2774 restoreCallingIdentity(identityToken);
2775 }
2776 }
2777
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002778 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002779 public void getAuthToken(
2780 IAccountManagerResponse response,
2781 final Account account,
2782 final String authTokenType,
2783 final boolean notifyOnAuthFailure,
2784 final boolean expectActivityLaunch,
2785 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002786 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002787 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2788 Log.v(TAG, "getAuthToken: " + account
2789 + ", response " + response
2790 + ", authTokenType " + authTokenType
2791 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2792 + ", expectActivityLaunch " + expectActivityLaunch
2793 + ", caller's uid " + Binder.getCallingUid()
2794 + ", pid " + Binder.getCallingPid());
2795 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002796 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002797 try {
2798 if (account == null) {
2799 Slog.w(TAG, "getAuthToken called with null account");
2800 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2801 return;
2802 }
2803 if (authTokenType == null) {
2804 Slog.w(TAG, "getAuthToken called with null authTokenType");
2805 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2806 return;
2807 }
2808 } catch (RemoteException e) {
2809 Slog.w(TAG, "Failed to report error back to the client." + e);
2810 return;
2811 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002812 int userId = UserHandle.getCallingUserId();
2813 long ident = Binder.clearCallingIdentity();
2814 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002815 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002816 try {
2817 accounts = getUserAccounts(userId);
2818 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2819 AuthenticatorDescription.newKey(account.type), accounts.userId);
2820 } finally {
2821 Binder.restoreCallingIdentity(ident);
2822 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002823
Costin Manolachea40c6302010-12-13 14:50:45 -08002824 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002825 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002826
2827 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002828 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002829 final boolean permissionGranted =
2830 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002831
Carlos Valdivia91979be2015-05-22 14:11:35 -07002832 // Get the calling package. We will use it for the purpose of caching.
2833 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002834 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002835 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002836 try {
2837 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2838 } finally {
2839 Binder.restoreCallingIdentity(ident);
2840 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002841 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2842 String msg = String.format(
2843 "Uid %s is attempting to illegally masquerade as package %s!",
2844 callerUid,
2845 callerPkg);
2846 throw new SecurityException(msg);
2847 }
2848
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002849 // let authenticator know the identity of the caller
2850 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2851 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002852
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002853 if (notifyOnAuthFailure) {
2854 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002855 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002856
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002857 long identityToken = clearCallingIdentity();
2858 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002859 // Distill the caller's package signatures into a single digest.
2860 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2861
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002862 // if the caller has permission, do the peek. otherwise go the more expensive
2863 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002864 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002865 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002866 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002867 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002868 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2869 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2870 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002871 onResult(response, result);
2872 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002873 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002874 }
2875
Carlos Valdivia91979be2015-05-22 14:11:35 -07002876 if (customTokens) {
2877 /*
2878 * Look up tokens in the new cache only if the loginOptions don't have parameters
2879 * outside of those expected to be injected by the AccountManager, e.g.
2880 * ANDORID_PACKAGE_NAME.
2881 */
2882 String token = readCachedTokenInternal(
2883 accounts,
2884 account,
2885 authTokenType,
2886 callerPkg,
2887 callerPkgSigDigest);
2888 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002889 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2890 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2891 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002892 Bundle result = new Bundle();
2893 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2894 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2895 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2896 onResult(response, result);
2897 return;
2898 }
2899 }
2900
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002901 new Session(
2902 accounts,
2903 response,
2904 account.type,
2905 expectActivityLaunch,
2906 false /* stripAuthTokenFromResult */,
2907 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002908 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002909 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002910 protected String toDebugString(long now) {
2911 if (loginOptions != null) loginOptions.keySet();
2912 return super.toDebugString(now) + ", getAuthToken"
Hui Yu139c2482018-08-10 15:37:51 -07002913 + ", " + account.toSafeString()
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002914 + ", authTokenType " + authTokenType
2915 + ", loginOptions " + loginOptions
2916 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2917 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002918
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002919 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002920 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002921 // If the caller doesn't have permission then create and return the
2922 // "grant permission" intent instead of the "getAuthToken" intent.
2923 if (!permissionGranted) {
2924 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2925 } else {
2926 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2927 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002928 }
2929
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002930 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002931 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002932 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002933 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002934 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002935 Intent intent = newGrantCredentialsPermissionIntent(
2936 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002937 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002938 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002939 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002940 authTokenType,
2941 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002942 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002943 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002944 onResult(bundle);
2945 return;
2946 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002947 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002948 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002949 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2950 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002951 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002952 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002953 "the type and name should not be empty");
2954 return;
2955 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002956 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002957 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002958 saveAuthTokenToDatabase(
2959 mAccounts,
2960 resultAccount,
2961 authTokenType,
2962 authToken);
2963 }
2964 long expiryMillis = result.getLong(
2965 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2966 if (customTokens
2967 && expiryMillis > System.currentTimeMillis()) {
2968 saveCachedToken(
2969 mAccounts,
2970 account,
2971 callerPkg,
2972 callerPkgSigDigest,
2973 authTokenType,
2974 authToken,
2975 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002976 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002977 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002978
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002979 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002980 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002981 /*
2982 * Make sure that the supplied intent is owned by the authenticator
2983 * giving it to the system. Otherwise a malicious authenticator could
2984 * have users launching arbitrary activities by tricking users to
2985 * interact with malicious notifications.
2986 */
tiansiminga8868bf2017-09-20 13:59:13 +08002987 if (!checkKeyIntent(
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002988 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08002989 intent)) {
2990 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
2991 "invalid intent in bundle returned");
2992 return;
2993 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002994 doNotification(
2995 mAccounts,
2996 account,
2997 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002998 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002999 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003000 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003001 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07003002 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003003 }.bind();
3004 } finally {
3005 restoreCallingIdentity(identityToken);
3006 }
Fred Quintana60307342009-03-24 22:48:12 -07003007 }
3008
Carlos Valdivia91979be2015-05-22 14:11:35 -07003009 private byte[] calculatePackageSignatureDigest(String callerPkg) {
3010 MessageDigest digester;
3011 try {
3012 digester = MessageDigest.getInstance("SHA-256");
3013 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
3014 callerPkg, PackageManager.GET_SIGNATURES);
3015 for (Signature sig : pkgInfo.signatures) {
3016 digester.update(sig.toByteArray());
3017 }
3018 } catch (NoSuchAlgorithmException x) {
3019 Log.wtf(TAG, "SHA-256 should be available", x);
3020 digester = null;
3021 } catch (NameNotFoundException e) {
3022 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
3023 digester = null;
3024 }
3025 return (digester == null) ? null : digester.digest();
3026 }
3027
Dianne Hackborn41203752012-08-31 14:05:51 -07003028 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003029 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003030 int uid = intent.getIntExtra(
3031 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3032 String authTokenType = intent.getStringExtra(
3033 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07003034 final String titleAndSubtitle =
3035 mContext.getString(R.string.permission_request_notification_with_subtitle,
3036 account.name);
3037 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07003038 String title = titleAndSubtitle;
3039 String subtitle = "";
3040 if (index > 0) {
3041 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04003042 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07003043 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07003044 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003045 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003046 Notification n =
3047 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3048 .setSmallIcon(android.R.drawable.stat_sys_warning)
3049 .setWhen(0)
3050 .setColor(contextForUser.getColor(
3051 com.android.internal.R.color.system_notification_accent_color))
3052 .setContentTitle(title)
3053 .setContentText(subtitle)
3054 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3055 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
3056 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003057 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003058 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003059 }
3060
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003061 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3062 int uid, AccountAuthenticatorResponse response, String authTokenType,
3063 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003064
3065 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003066
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003067 if (startInNewTask) {
3068 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3069 // Since it was set in Eclair+ we can't change it without breaking apps using
3070 // the intent from a non-Activity context. This is the default behavior.
3071 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3072 }
Chris Wren717a8812017-03-31 15:34:39 -04003073 intent.addCategory(getCredentialPermissionNotificationId(account,
3074 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003075 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003076 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3077 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003078 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003079
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003080 return intent;
3081 }
3082
Chris Wren717a8812017-03-31 15:34:39 -04003083 private NotificationId getCredentialPermissionNotificationId(Account account,
3084 String authTokenType, int uid) {
3085 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003086 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003087 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003088 final Pair<Pair<Account, String>, Integer> key =
3089 new Pair<Pair<Account, String>, Integer>(
3090 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04003091 nId = accounts.credentialsPermissionNotificationIds.get(key);
3092 if (nId == null) {
3093 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3094 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
3095 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3096 nId = new NotificationId(tag, id);
3097 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003098 }
3099 }
Chris Wren717a8812017-03-31 15:34:39 -04003100 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003101 }
3102
Chris Wren717a8812017-03-31 15:34:39 -04003103 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3104 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08003105 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04003106 nId = accounts.signinRequiredNotificationIds.get(account);
3107 if (nId == null) {
3108 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3109 + ":" + account.hashCode();
3110 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3111 nId = new NotificationId(tag, id);
3112 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003113 }
3114 }
Chris Wren717a8812017-03-31 15:34:39 -04003115 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003116 }
3117
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003118 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07003119 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003120 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003121 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003122 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003123 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3124 Log.v(TAG, "addAccount: accountType " + accountType
3125 + ", response " + response
3126 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003127 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003128 + ", expectActivityLaunch " + expectActivityLaunch
3129 + ", caller's uid " + Binder.getCallingUid()
3130 + ", pid " + Binder.getCallingPid());
3131 }
Fred Quintana382601f2010-03-25 12:25:10 -07003132 if (response == null) throw new IllegalArgumentException("response is null");
3133 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003134
Amith Yamasani71e6c692013-03-24 17:39:28 -07003135 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003136 final int uid = Binder.getCallingUid();
3137 final int userId = UserHandle.getUserId(uid);
3138 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003139 try {
3140 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3141 "User is not allowed to add an account!");
3142 } catch (RemoteException re) {
3143 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003144 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003145 return;
3146 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003147 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003148 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003149 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3150 "User cannot modify accounts of this type (policy).");
3151 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003152 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003153 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3154 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003155 return;
3156 }
3157
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003158 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003159 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3160 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3161 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3162
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003163 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003164 long identityToken = clearCallingIdentity();
3165 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003166 UserAccounts accounts = getUserAccounts(usrId);
3167 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003168 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3169 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003170 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003171 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003172 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003173 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003174 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003175 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003176 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003177 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003178
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003179 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003180 protected String toDebugString(long now) {
3181 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003182 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003183 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003184 }
3185 }.bind();
3186 } finally {
3187 restoreCallingIdentity(identityToken);
3188 }
Fred Quintana60307342009-03-24 22:48:12 -07003189 }
3190
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003191 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003192 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3193 final String authTokenType, final String[] requiredFeatures,
3194 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003195 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003196 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003197 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3198 Log.v(TAG, "addAccount: accountType " + accountType
3199 + ", response " + response
3200 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003201 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003202 + ", expectActivityLaunch " + expectActivityLaunch
3203 + ", caller's uid " + Binder.getCallingUid()
3204 + ", pid " + Binder.getCallingPid()
3205 + ", for user id " + userId);
3206 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003207 Preconditions.checkArgument(response != null, "response cannot be null");
3208 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003209 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003210 if (isCrossUser(callingUid, userId)) {
3211 throw new SecurityException(
3212 String.format(
3213 "User %s trying to add account for %s" ,
3214 UserHandle.getCallingUserId(),
3215 userId));
3216 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003217
3218 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003219 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003220 try {
3221 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3222 "User is not allowed to add an account!");
3223 } catch (RemoteException re) {
3224 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003225 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003226 return;
3227 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003228 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003229 try {
3230 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3231 "User cannot modify accounts of this type (policy).");
3232 } catch (RemoteException re) {
3233 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003234 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3235 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003236 return;
3237 }
3238
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003239 final int pid = Binder.getCallingPid();
3240 final int uid = Binder.getCallingUid();
3241 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3242 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3243 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3244
3245 long identityToken = clearCallingIdentity();
3246 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003247 UserAccounts accounts = getUserAccounts(userId);
3248 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003249 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3250 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003251 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003252 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003253 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003254 @Override
3255 public void run() throws RemoteException {
3256 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3257 options);
3258 }
3259
3260 @Override
3261 protected String toDebugString(long now) {
3262 return super.toDebugString(now) + ", addAccount"
3263 + ", accountType " + accountType
3264 + ", requiredFeatures "
3265 + (requiredFeatures != null
3266 ? TextUtils.join(",", requiredFeatures)
3267 : null);
3268 }
3269 }.bind();
3270 } finally {
3271 restoreCallingIdentity(identityToken);
3272 }
3273 }
3274
Sandra Kwan78812282015-11-04 11:19:47 -08003275 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003276 public void startAddAccountSession(
3277 final IAccountManagerResponse response,
3278 final String accountType,
3279 final String authTokenType,
3280 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003281 final boolean expectActivityLaunch,
3282 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003283 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003284 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3285 Log.v(TAG,
3286 "startAddAccountSession: accountType " + accountType
3287 + ", response " + response
3288 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003289 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003290 + ", expectActivityLaunch " + expectActivityLaunch
3291 + ", caller's uid " + Binder.getCallingUid()
3292 + ", pid " + Binder.getCallingPid());
3293 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003294 Preconditions.checkArgument(response != null, "response cannot be null");
3295 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003296
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003297 final int uid = Binder.getCallingUid();
3298 final int userId = UserHandle.getUserId(uid);
3299 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003300 try {
3301 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3302 "User is not allowed to add an account!");
3303 } catch (RemoteException re) {
3304 }
3305 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3306 return;
3307 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003308 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003309 try {
3310 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3311 "User cannot modify accounts of this type (policy).");
3312 } catch (RemoteException re) {
3313 }
3314 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3315 userId);
3316 return;
3317 }
Sandra Kwan78812282015-11-04 11:19:47 -08003318 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003319 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3320 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3321 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3322
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003323 // Check to see if the Password should be included to the caller.
3324 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3325 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003326 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003327
Sandra Kwan78812282015-11-04 11:19:47 -08003328 long identityToken = clearCallingIdentity();
3329 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003330 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003331 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3332 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003333 new StartAccountSession(
3334 accounts,
3335 response,
3336 accountType,
3337 expectActivityLaunch,
3338 null /* accountName */,
3339 false /* authDetailsRequired */,
3340 true /* updateLastAuthenticationTime */,
3341 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003342 @Override
3343 public void run() throws RemoteException {
3344 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3345 requiredFeatures, options);
3346 }
3347
3348 @Override
3349 protected String toDebugString(long now) {
3350 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3351 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3352 + accountType + ", requiredFeatures "
3353 + (requiredFeatures != null ? requiredFeaturesStr : null);
3354 }
3355 }.bind();
3356 } finally {
3357 restoreCallingIdentity(identityToken);
3358 }
3359 }
3360
3361 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3362 private abstract class StartAccountSession extends Session {
3363
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003364 private final boolean mIsPasswordForwardingAllowed;
3365
3366 public StartAccountSession(
3367 UserAccounts accounts,
3368 IAccountManagerResponse response,
3369 String accountType,
3370 boolean expectActivityLaunch,
3371 String accountName,
3372 boolean authDetailsRequired,
3373 boolean updateLastAuthenticationTime,
3374 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003375 super(accounts, response, accountType, expectActivityLaunch,
3376 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3377 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003378 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003379 }
3380
3381 @Override
3382 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003383 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003384 mNumResults++;
3385 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003386 if (result != null
3387 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08003388 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003389 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08003390 intent)) {
3391 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3392 "invalid intent in bundle returned");
3393 return;
3394 }
Sandra Kwan78812282015-11-04 11:19:47 -08003395 }
Sandra Kwan78812282015-11-04 11:19:47 -08003396 IAccountManagerResponse response;
3397 if (mExpectActivityLaunch && result != null
3398 && result.containsKey(AccountManager.KEY_INTENT)) {
3399 response = mResponse;
3400 } else {
3401 response = getResponseAndClose();
3402 }
3403 if (response == null) {
3404 return;
3405 }
3406 if (result == null) {
3407 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3408 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3409 + response);
3410 }
3411 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3412 "null bundle returned");
3413 return;
3414 }
3415
3416 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3417 // All AccountManager error codes are greater
3418 // than 0
3419 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3420 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3421 return;
3422 }
3423
Hongming Jin368aa192016-07-29 14:29:54 -07003424 // Omit passwords if the caller isn't permitted to see them.
3425 if (!mIsPasswordForwardingAllowed) {
3426 result.remove(AccountManager.KEY_PASSWORD);
3427 }
3428
Sandra Kwan78812282015-11-04 11:19:47 -08003429 // Strip auth token from result.
3430 result.remove(AccountManager.KEY_AUTHTOKEN);
3431
3432 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3433 Log.v(TAG,
3434 getClass().getSimpleName() + " calling onResult() on response " + response);
3435 }
3436
3437 // Get the session bundle created by authenticator. The
3438 // bundle contains data necessary for finishing the session
3439 // later. The session bundle will be encrypted here and
3440 // decrypted later when trying to finish the session.
3441 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3442 if (sessionBundle != null) {
3443 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3444 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003445 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003446 Log.w(TAG, "Account type in session bundle doesn't match request.");
3447 }
3448 // Add accountType info to session bundle. This will
3449 // override any value set by authenticator.
3450 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3451
3452 // Encrypt session bundle before returning to caller.
3453 try {
3454 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3455 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3456 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3457 } catch (GeneralSecurityException e) {
3458 if (Log.isLoggable(TAG, Log.DEBUG)) {
3459 Log.v(TAG, "Failed to encrypt session bundle!", e);
3460 }
3461 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3462 "failed to encrypt session bundle");
3463 return;
3464 }
3465 }
3466
3467 sendResponse(response, result);
3468 }
3469 }
3470
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003471 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003472 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003473 @NonNull Bundle sessionBundle,
3474 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003475 Bundle appInfo,
3476 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003477 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003478 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003479 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3480 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003481 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003482 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003483 + ", caller's uid " + callingUid
3484 + ", caller's user id " + UserHandle.getCallingUserId()
3485 + ", pid " + Binder.getCallingPid()
3486 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003487 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003488 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003489 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3490 // Account type is added to it before encryption.
3491 if (sessionBundle == null || sessionBundle.size() == 0) {
3492 throw new IllegalArgumentException("sessionBundle is empty");
3493 }
3494
Dmitry Dementyev52745472016-12-02 10:27:45 -08003495 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003496 if (isCrossUser(callingUid, userId)) {
3497 throw new SecurityException(
3498 String.format(
3499 "User %s trying to finish session for %s without cross user permission",
3500 UserHandle.getCallingUserId(),
3501 userId));
3502 }
3503
Sandra Kwan0b84b452016-01-20 15:25:42 -08003504 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003505 sendErrorResponse(response,
3506 AccountManager.ERROR_CODE_USER_RESTRICTED,
3507 "User is not allowed to add an account!");
3508 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3509 return;
3510 }
3511
3512 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003513 final Bundle decryptedBundle;
3514 final String accountType;
3515 // First decrypt session bundle to get account type for checking permission.
3516 try {
3517 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3518 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3519 if (decryptedBundle == null) {
3520 sendErrorResponse(
3521 response,
3522 AccountManager.ERROR_CODE_BAD_REQUEST,
3523 "failed to decrypt session bundle");
3524 return;
3525 }
3526 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3527 // Account type cannot be null. This should not happen if session bundle was created
3528 // properly by #StartAccountSession.
3529 if (TextUtils.isEmpty(accountType)) {
3530 sendErrorResponse(
3531 response,
3532 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3533 "accountType is empty");
3534 return;
3535 }
3536
3537 // If by any chances, decryptedBundle contains colliding keys with
3538 // system info
3539 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3540 // update credentials flow, we should replace with the new values of the current call.
3541 if (appInfo != null) {
3542 decryptedBundle.putAll(appInfo);
3543 }
3544
3545 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003546 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003547 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3548 } catch (GeneralSecurityException e) {
3549 if (Log.isLoggable(TAG, Log.DEBUG)) {
3550 Log.v(TAG, "Failed to decrypt session bundle!", e);
3551 }
3552 sendErrorResponse(
3553 response,
3554 AccountManager.ERROR_CODE_BAD_REQUEST,
3555 "failed to decrypt session bundle");
3556 return;
3557 }
3558
Sandra Kwan0b84b452016-01-20 15:25:42 -08003559 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003560 sendErrorResponse(
3561 response,
3562 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3563 "User cannot modify accounts of this type (policy).");
3564 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3565 userId);
3566 return;
3567 }
3568
3569 long identityToken = clearCallingIdentity();
3570 try {
3571 UserAccounts accounts = getUserAccounts(userId);
3572 logRecordWithUid(
3573 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003574 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3575 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003576 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003577 new Session(
3578 accounts,
3579 response,
3580 accountType,
3581 expectActivityLaunch,
3582 true /* stripAuthTokenFromResult */,
3583 null /* accountName */,
3584 false /* authDetailsRequired */,
3585 true /* updateLastAuthenticationTime */) {
3586 @Override
3587 public void run() throws RemoteException {
3588 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3589 }
3590
3591 @Override
3592 protected String toDebugString(long now) {
3593 return super.toDebugString(now)
3594 + ", finishSession"
3595 + ", accountType " + accountType;
3596 }
3597 }.bind();
3598 } finally {
3599 restoreCallingIdentity(identityToken);
3600 }
3601 }
3602
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003603 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003604 final DevicePolicyManagerInternal dpmi =
3605 LocalServices.getService(DevicePolicyManagerInternal.class);
3606 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003607 if (dpmi == null) {
3608 intent = getDefaultCantAddAccountIntent(errorCode);
3609 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003610 intent = dpmi.createUserRestrictionSupportIntent(userId,
3611 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3612 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3613 intent = dpmi.createShowAdminSupportIntent(userId, false);
3614 }
3615 if (intent == null) {
3616 intent = getDefaultCantAddAccountIntent(errorCode);
3617 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003618 long identityToken = clearCallingIdentity();
3619 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003620 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003621 } finally {
3622 restoreCallingIdentity(identityToken);
3623 }
3624 }
3625
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003626 /**
3627 * Called when we don't know precisely who is preventing us from adding an account.
3628 */
3629 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3630 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3631 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3632 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3633 return cantAddAccount;
3634 }
3635
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003636 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003637 public void confirmCredentialsAsUser(
3638 IAccountManagerResponse response,
3639 final Account account,
3640 final Bundle options,
3641 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003642 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003643 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003644 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003645 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3646 Log.v(TAG, "confirmCredentials: " + account
3647 + ", response " + response
3648 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003649 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003650 + ", pid " + Binder.getCallingPid());
3651 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003652 // Only allow the system process to read accounts of other users
3653 if (isCrossUser(callingUid, userId)) {
3654 throw new SecurityException(
3655 String.format(
3656 "User %s trying to confirm account credentials for %s" ,
3657 UserHandle.getCallingUserId(),
3658 userId));
3659 }
Fred Quintana382601f2010-03-25 12:25:10 -07003660 if (response == null) throw new IllegalArgumentException("response is null");
3661 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003662 long identityToken = clearCallingIdentity();
3663 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003664 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003665 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003666 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003667 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003668 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003669 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003670 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003671 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003672 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003673 protected String toDebugString(long now) {
3674 return super.toDebugString(now) + ", confirmCredentials"
Hui Yu139c2482018-08-10 15:37:51 -07003675 + ", " + account.toSafeString();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003676 }
3677 }.bind();
3678 } finally {
3679 restoreCallingIdentity(identityToken);
3680 }
Fred Quintana60307342009-03-24 22:48:12 -07003681 }
3682
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003683 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003684 public void updateCredentials(IAccountManagerResponse response, final Account account,
3685 final String authTokenType, final boolean expectActivityLaunch,
3686 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003687 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003688 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3689 Log.v(TAG, "updateCredentials: " + account
3690 + ", response " + response
3691 + ", authTokenType " + authTokenType
3692 + ", expectActivityLaunch " + expectActivityLaunch
3693 + ", caller's uid " + Binder.getCallingUid()
3694 + ", pid " + Binder.getCallingPid());
3695 }
Fred Quintana382601f2010-03-25 12:25:10 -07003696 if (response == null) throw new IllegalArgumentException("response is null");
3697 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003698 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003699 long identityToken = clearCallingIdentity();
3700 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003701 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003702 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003703 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003704 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003705 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003706 public void run() throws RemoteException {
3707 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3708 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003709 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003710 protected String toDebugString(long now) {
3711 if (loginOptions != null) loginOptions.keySet();
3712 return super.toDebugString(now) + ", updateCredentials"
Hui Yu139c2482018-08-10 15:37:51 -07003713 + ", " + account.toSafeString()
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003714 + ", authTokenType " + authTokenType
3715 + ", loginOptions " + loginOptions;
3716 }
3717 }.bind();
3718 } finally {
3719 restoreCallingIdentity(identityToken);
3720 }
Fred Quintana60307342009-03-24 22:48:12 -07003721 }
3722
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003723 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003724 public void startUpdateCredentialsSession(
3725 IAccountManagerResponse response,
3726 final Account account,
3727 final String authTokenType,
3728 final boolean expectActivityLaunch,
3729 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003730 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003731 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3732 Log.v(TAG,
3733 "startUpdateCredentialsSession: " + account + ", response " + response
3734 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3735 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3736 + ", pid " + Binder.getCallingPid());
3737 }
3738 if (response == null) {
3739 throw new IllegalArgumentException("response is null");
3740 }
3741 if (account == null) {
3742 throw new IllegalArgumentException("account is null");
3743 }
Sandra Kwana578d112015-12-16 16:01:43 -08003744
3745 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003746 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003747
3748 // Check to see if the Password should be included to the caller.
3749 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3750 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003751 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003752
Sandra Kwane68c37e2015-11-12 17:11:49 -08003753 long identityToken = clearCallingIdentity();
3754 try {
3755 UserAccounts accounts = getUserAccounts(userId);
3756 new StartAccountSession(
3757 accounts,
3758 response,
3759 account.type,
3760 expectActivityLaunch,
3761 account.name,
3762 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003763 true /* updateLastCredentialTime */,
3764 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003765 @Override
3766 public void run() throws RemoteException {
3767 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3768 loginOptions);
3769 }
3770
3771 @Override
3772 protected String toDebugString(long now) {
3773 if (loginOptions != null)
3774 loginOptions.keySet();
3775 return super.toDebugString(now)
3776 + ", startUpdateCredentialsSession"
Hui Yu139c2482018-08-10 15:37:51 -07003777 + ", " + account.toSafeString()
Sandra Kwane68c37e2015-11-12 17:11:49 -08003778 + ", authTokenType " + authTokenType
3779 + ", loginOptions " + loginOptions;
3780 }
3781 }.bind();
3782 } finally {
3783 restoreCallingIdentity(identityToken);
3784 }
3785 }
3786
3787 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003788 public void isCredentialsUpdateSuggested(
3789 IAccountManagerResponse response,
3790 final Account account,
3791 final String statusToken) {
3792 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3793 Log.v(TAG,
3794 "isCredentialsUpdateSuggested: " + account + ", response " + response
3795 + ", caller's uid " + Binder.getCallingUid()
3796 + ", pid " + Binder.getCallingPid());
3797 }
3798 if (response == null) {
3799 throw new IllegalArgumentException("response is null");
3800 }
3801 if (account == null) {
3802 throw new IllegalArgumentException("account is null");
3803 }
3804 if (TextUtils.isEmpty(statusToken)) {
3805 throw new IllegalArgumentException("status token is empty");
3806 }
3807
Sandra Kwan390c9d22016-01-12 14:13:37 -08003808 int usrId = UserHandle.getCallingUserId();
3809 long identityToken = clearCallingIdentity();
3810 try {
3811 UserAccounts accounts = getUserAccounts(usrId);
3812 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3813 false /* stripAuthTokenFromResult */, account.name,
3814 false /* authDetailsRequired */) {
3815 @Override
3816 protected String toDebugString(long now) {
3817 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
Hui Yu139c2482018-08-10 15:37:51 -07003818 + ", " + account.toSafeString();
Sandra Kwan390c9d22016-01-12 14:13:37 -08003819 }
3820
3821 @Override
3822 public void run() throws RemoteException {
3823 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3824 }
3825
3826 @Override
3827 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003828 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003829 IAccountManagerResponse response = getResponseAndClose();
3830 if (response == null) {
3831 return;
3832 }
3833
3834 if (result == null) {
3835 sendErrorResponse(
3836 response,
3837 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3838 "null bundle");
3839 return;
3840 }
3841
3842 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3843 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3844 + response);
3845 }
3846 // Check to see if an error occurred. We know if an error occurred because all
3847 // error codes are greater than 0.
3848 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3849 sendErrorResponse(response,
3850 result.getInt(AccountManager.KEY_ERROR_CODE),
3851 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3852 return;
3853 }
3854 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3855 sendErrorResponse(
3856 response,
3857 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3858 "no result in response");
3859 return;
3860 }
3861 final Bundle newResult = new Bundle();
3862 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3863 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3864 sendResponse(response, newResult);
3865 }
3866 }.bind();
3867 } finally {
3868 restoreCallingIdentity(identityToken);
3869 }
3870 }
3871
3872 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003873 public void editProperties(IAccountManagerResponse response, final String accountType,
3874 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003875 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003876 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3877 Log.v(TAG, "editProperties: accountType " + accountType
3878 + ", response " + response
3879 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003880 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003881 + ", pid " + Binder.getCallingPid());
3882 }
Fred Quintana382601f2010-03-25 12:25:10 -07003883 if (response == null) throw new IllegalArgumentException("response is null");
3884 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003885 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003886 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3887 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003888 String msg = String.format(
3889 "uid %s cannot edit authenticator properites for account type: %s",
3890 callingUid,
3891 accountType);
3892 throw new SecurityException(msg);
3893 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003894 long identityToken = clearCallingIdentity();
3895 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003896 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003897 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003898 true /* stripAuthTokenFromResult */, null /* accountName */,
3899 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003900 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003901 public void run() throws RemoteException {
3902 mAuthenticator.editProperties(this, mAccountType);
3903 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003904 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003905 protected String toDebugString(long now) {
3906 return super.toDebugString(now) + ", editProperties"
3907 + ", accountType " + accountType;
3908 }
3909 }.bind();
3910 } finally {
3911 restoreCallingIdentity(identityToken);
3912 }
Fred Quintana60307342009-03-24 22:48:12 -07003913 }
3914
Amith Yamasani12747872015-12-07 14:19:49 -08003915 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003916 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3917 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003918 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003919 throw new SecurityException("Can be called only by system UID");
3920 }
3921 Preconditions.checkNotNull(account, "account cannot be null");
3922 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3923 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3924
3925 final int userId = userHandle.getIdentifier();
3926
3927 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3928
3929 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003930 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003931 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003932 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003933 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003934 return false;
3935 }
3936 }
3937
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003938 // Returns package with oldest target SDK for given UID.
3939 private String getPackageNameForUid(int uid) {
3940 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3941 if (ArrayUtils.isEmpty(packageNames)) {
3942 return null;
3943 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003944 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003945 if (packageNames.length == 1) {
3946 return packageName;
3947 }
3948 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003949 int oldestVersion = Integer.MAX_VALUE;
3950 for (String name : packageNames) {
3951 try {
3952 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3953 if (applicationInfo != null) {
3954 int version = applicationInfo.targetSdkVersion;
3955 if (version < oldestVersion) {
3956 oldestVersion = version;
3957 packageName = name;
3958 }
3959 }
3960 } catch (NameNotFoundException e) {
3961 // skip
3962 }
3963 }
3964 return packageName;
3965 }
3966
Svet Ganovf6d424f12016-09-20 20:18:53 -07003967 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3968 int uid) {
3969 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003970 packageName = getPackageNameForUid(uid);
3971 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003972 return false;
3973 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003974 }
3975
3976 // Use null token which means any token. Having a token means the package
3977 // is trusted by the authenticator, hence it is fine to access the account.
3978 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3979 return true;
3980 }
3981 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003982 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003983
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003984 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003985 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003986 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003987 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003988 }
3989
3990 @Override
3991 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3992 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003993 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003994 throw new SecurityException("Can be called only by system UID");
3995 }
3996
3997 Preconditions.checkNotNull(account, "account cannot be null");
3998 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3999 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
4000
4001 final int userId = userHandle.getIdentifier();
4002
4003 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
4004
4005 final int uid;
4006 try {
4007 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
4008 } catch (NameNotFoundException e) {
4009 Slog.e(TAG, "Unknown package " + packageName);
4010 return null;
4011 }
4012
4013 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
4014
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07004015 final long identity = Binder.clearCallingIdentity();
4016 try {
4017 return PendingIntent.getActivityAsUser(
4018 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
4019 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
4020 null, new UserHandle(userId)).getIntentSender();
4021 } finally {
4022 Binder.restoreCallingIdentity(identity);
4023 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004024 }
4025
4026 private Intent newRequestAccountAccessIntent(Account account, String packageName,
4027 int uid, RemoteCallback callback) {
4028 return newGrantCredentialsPermissionIntent(account, packageName, uid,
4029 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
4030 @Override
4031 public void onResult(Bundle value) throws RemoteException {
4032 handleAuthenticatorResponse(true);
4033 }
4034
4035 @Override
4036 public void onRequestContinued() {
4037 /* ignore */
4038 }
4039
4040 @Override
4041 public void onError(int errorCode, String errorMessage) throws RemoteException {
4042 handleAuthenticatorResponse(false);
4043 }
4044
4045 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4046 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07004047 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004048 UserHandle.getUserHandleForUid(uid));
4049 if (callback != null) {
4050 Bundle result = new Bundle();
4051 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4052 callback.sendResult(result);
4053 }
4054 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07004055 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004056 }
4057
4058 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08004059 public boolean someUserHasAccount(@NonNull final Account account) {
4060 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4061 throw new SecurityException("Only system can check for accounts across users");
4062 }
4063 final long token = Binder.clearCallingIdentity();
4064 try {
4065 AccountAndUser[] allAccounts = getAllAccounts();
4066 for (int i = allAccounts.length - 1; i >= 0; i--) {
4067 if (allAccounts[i].account.equals(account)) {
4068 return true;
4069 }
4070 }
4071 return false;
4072 } finally {
4073 Binder.restoreCallingIdentity(token);
4074 }
4075 }
4076
Fred Quintana33269202009-04-20 16:05:10 -07004077 private class GetAccountsByTypeAndFeatureSession extends Session {
4078 private final String[] mFeatures;
4079 private volatile Account[] mAccountsOfType = null;
4080 private volatile ArrayList<Account> mAccountsWithFeatures = null;
4081 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004082 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004083 private final String mPackageName;
sunjianf29d5492017-05-11 15:42:31 -07004084 private final boolean mIncludeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004085
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004086 public GetAccountsByTypeAndFeatureSession(
4087 UserAccounts accounts,
4088 IAccountManagerResponse response,
4089 String type,
4090 String[] features,
4091 int callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004092 String packageName,
4093 boolean includeManagedNotVisible) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004094 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004095 true /* stripAuthTokenFromResult */, null /* accountName */,
4096 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004097 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07004098 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004099 mPackageName = packageName;
sunjianf29d5492017-05-11 15:42:31 -07004100 mIncludeManagedNotVisible = includeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004101 }
4102
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004103 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004104 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004105 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
sunjianf29d5492017-05-11 15:42:31 -07004106 mCallingUid, mPackageName, mIncludeManagedNotVisible);
Fred Quintana33269202009-04-20 16:05:10 -07004107 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07004108 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07004109 mCurrentAccount = 0;
4110
4111 checkAccount();
4112 }
4113
4114 public void checkAccount() {
4115 if (mCurrentAccount >= mAccountsOfType.length) {
4116 sendResult();
4117 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07004118 }
Fred Quintana33269202009-04-20 16:05:10 -07004119
Fred Quintana29e94b82010-03-10 12:11:51 -08004120 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4121 if (accountAuthenticator == null) {
4122 // It is possible that the authenticator has died, which is indicated by
4123 // mAuthenticator being set to null. If this happens then just abort.
4124 // There is no need to send back a result or error in this case since
4125 // that already happened when mAuthenticator was cleared.
4126 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4127 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4128 + " connected to the authenticator, " + toDebugString());
4129 }
4130 return;
4131 }
Fred Quintana33269202009-04-20 16:05:10 -07004132 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004133 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004134 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004135 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004136 }
4137 }
4138
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004139 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004140 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004141 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004142 mNumResults++;
4143 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004144 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004145 return;
4146 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004147 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004148 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4149 }
4150 mCurrentAccount++;
4151 checkAccount();
4152 }
4153
4154 public void sendResult() {
4155 IAccountManagerResponse response = getResponseAndClose();
4156 if (response != null) {
4157 try {
4158 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4159 for (int i = 0; i < accounts.length; i++) {
4160 accounts[i] = mAccountsWithFeatures.get(i);
4161 }
Fred Quintana56285a62010-12-02 14:20:51 -08004162 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4163 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4164 + response);
4165 }
Fred Quintana33269202009-04-20 16:05:10 -07004166 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004167 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004168 response.onResult(result);
4169 } catch (RemoteException e) {
4170 // if the caller is dead then there is no one to care about remote exceptions
4171 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4172 Log.v(TAG, "failure while notifying response", e);
4173 }
4174 }
4175 }
4176 }
4177
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004178 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004179 protected String toDebugString(long now) {
4180 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4181 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4182 }
4183 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004184
Amith Yamasani04e0d262012-02-14 11:50:53 -08004185 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004186 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004187 * @hide
4188 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004189 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004190 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004191 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004192 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004193 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4194 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004195 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004196 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004197 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004198 long identityToken = clearCallingIdentity();
4199 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004200 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004201 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004202 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004203 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004204 opPackageName,
4205 visibleAccountTypes,
4206 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004207 } finally {
4208 restoreCallingIdentity(identityToken);
4209 }
4210 }
4211
Amith Yamasanif29f2362012-04-05 18:29:52 -07004212 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004213 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004214 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004215 * @hide
4216 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004217 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004218 public AccountAndUser[] getRunningAccounts() {
4219 final int[] runningUserIds;
4220 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004221 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004222 } catch (RemoteException e) {
4223 // Running in system_server; should never happen
4224 throw new RuntimeException(e);
4225 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004226 return getAccounts(runningUserIds);
4227 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004228
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004229 /**
4230 * Returns accounts for all users, ignores visibility values.
4231 *
4232 * @hide
4233 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004234 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004235 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004236 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004237 final int[] userIds = new int[users.size()];
4238 for (int i = 0; i < userIds.length; i++) {
4239 userIds[i] = users.get(i).id;
4240 }
4241 return getAccounts(userIds);
4242 }
4243
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004244 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004245 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004246 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004247 for (int userId : userIds) {
4248 UserAccounts userAccounts = getUserAccounts(userId);
4249 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004250 Account[] accounts = getAccountsFromCache(
4251 userAccounts,
4252 null /* type */,
4253 Binder.getCallingUid(),
4254 null /* packageName */,
4255 false /* include managed not visible*/);
4256 for (Account account : accounts) {
4257 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004258 }
4259 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004260
4261 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4262 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004263 }
4264
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004265 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004266 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004267 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004268 int callingUid = Binder.getCallingUid();
4269 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004270 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004271 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004272 }
4273
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004274 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004275 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004276 String type,
4277 int userId,
4278 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004279 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004280 String opPackageName,
4281 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004282 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004283 // Only allow the system process to read accounts of other users
4284 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004285 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004286 && mContext.checkCallingOrSelfPermission(
4287 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4288 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004289 throw new SecurityException("User " + UserHandle.getCallingUserId()
4290 + " trying to get account for " + userId);
4291 }
4292
Fred Quintana56285a62010-12-02 14:20:51 -08004293 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4294 Log.v(TAG, "getAccounts: accountType " + type
4295 + ", caller's uid " + Binder.getCallingUid()
4296 + ", pid " + Binder.getCallingPid());
4297 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004298
4299 // If the original calling app was using account choosing activity
4300 // provided by the framework or authenticator we'll passing in
4301 // the original caller's uid here, which is what should be used for filtering.
4302 List<String> managedTypes =
4303 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4304 if (packageUid != -1 &&
4305 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4306 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004307 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004308 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004309 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004310 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4311 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004312 if (visibleAccountTypes.isEmpty()
4313 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004314 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004315 } else if (visibleAccountTypes.contains(type)) {
4316 // Prune the list down to just the requested type.
4317 visibleAccountTypes = new ArrayList<>();
4318 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004319 } // else aggregate all the visible accounts (it won't matter if the
4320 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004321
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004322 long identityToken = clearCallingIdentity();
4323 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004324 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004325 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004326 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004327 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004328 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004329 visibleAccountTypes,
4330 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004331 } finally {
4332 restoreCallingIdentity(identityToken);
4333 }
4334 }
4335
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004336 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004337 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004338 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004339 int callingUid,
4340 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004341 List<String> visibleAccountTypes,
4342 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004343 ArrayList<Account> visibleAccounts = new ArrayList<>();
4344 for (String visibleType : visibleAccountTypes) {
4345 Account[] accountsForType = getAccountsFromCache(
4346 userAccounts, visibleType, callingUid, callingPackage,
4347 includeUserManagedNotVisible);
4348 if (accountsForType != null) {
4349 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004350 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004351 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004352 Account[] result = new Account[visibleAccounts.size()];
4353 for (int i = 0; i < visibleAccounts.size(); i++) {
4354 result[i] = visibleAccounts.get(i);
4355 }
4356 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004357 }
4358
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004359 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004360 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4361 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004362 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004363 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004364 for (Account account : accounts) {
4365 addSharedAccountAsUser(account, userId);
4366 }
4367 }
4368
4369 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004370 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004371 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004372 accounts.accountsDb.deleteSharedAccount(account);
4373 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004374 if (accountId < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07004375 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Amith Yamasani67df64b2012-12-14 12:09:36 -08004376 + ", skipping the DB insert failed");
4377 return false;
4378 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004379 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4380 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004381 return true;
4382 }
4383
4384 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004385 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4386 userId = handleIncomingUser(userId);
4387 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004388 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4389 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004390 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004391 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004392 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004393 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004394 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004395 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004396 }
4397 return r > 0;
4398 }
4399
4400 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004401 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004402 return removeSharedAccountAsUser(account, userId, getCallingUid());
4403 }
4404
4405 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004406 userId = handleIncomingUser(userId);
4407 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004408 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4409 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004410 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004411 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004412 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004413 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004414 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004415 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004416 }
4417
4418 @Override
4419 public Account[] getSharedAccountsAsUser(int userId) {
4420 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004421 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004422 synchronized (accounts.dbLock) {
4423 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4424 Account[] accountArray = new Account[accountList.size()];
4425 accountList.toArray(accountArray);
4426 return accountArray;
4427 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004428 }
4429
4430 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004431 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004432 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004433 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004434 }
4435
Amith Yamasani27db4682013-03-30 17:07:47 -07004436 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004437 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004438 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004439 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004440 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004441 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004442 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4443 + callingUid + " with uid=" + uid);
4444 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004445 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004446 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004447 }
4448
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004449 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004450 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004451 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4452 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004453 int callingUid = Binder.getCallingUid();
4454 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004455 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004456 int packageUid = -1;
4457 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004458 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4459 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004460 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004461 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004462 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004463 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004464 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4465 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004466 }
sunjiand62dc392017-06-01 12:05:59 -07004467 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4468 return getAccountsAsUserForPackage(type, userId,
4469 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4470 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004471 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004472 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004473 }
4474
sunjianf29d5492017-05-11 15:42:31 -07004475 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4476 if (accounts.length < 1) return false;
4477 if (accounts.length > 1) return true;
4478 Account account = accounts[0];
4479 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4480 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4481 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4482 return false;
4483 }
4484
4485 private void startChooseAccountActivityWithAccounts(
sunjianbdabd402017-06-06 17:54:07 -07004486 IAccountManagerResponse response, Account[] accounts, String callingPackage) {
sunjianf29d5492017-05-11 15:42:31 -07004487 Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4488 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4489 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4490 new AccountManagerResponse(response));
sunjianbdabd402017-06-06 17:54:07 -07004491 intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004492
4493 mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4494 }
4495
4496 private void handleGetAccountsResult(
4497 IAccountManagerResponse response,
4498 Account[] accounts,
4499 String callingPackage) {
4500
4501 if (needToStartChooseAccountActivity(accounts, callingPackage)) {
sunjianbdabd402017-06-06 17:54:07 -07004502 startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004503 return;
4504 }
4505 if (accounts.length == 1) {
4506 Bundle bundle = new Bundle();
4507 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4508 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4509 onResult(response, bundle);
4510 return;
4511 }
4512 // No qualified account exists, return an empty Bundle.
4513 onResult(response, new Bundle());
4514 }
4515
4516 @Override
4517 public void getAccountByTypeAndFeatures(
4518 IAccountManagerResponse response,
4519 String accountType,
4520 String[] features,
4521 String opPackageName) {
4522
4523 int callingUid = Binder.getCallingUid();
4524 mAppOpsManager.checkPackage(callingUid, opPackageName);
4525 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4526 Log.v(TAG, "getAccount: accountType " + accountType
4527 + ", response " + response
4528 + ", features " + Arrays.toString(features)
4529 + ", caller's uid " + callingUid
4530 + ", pid " + Binder.getCallingPid());
4531 }
4532 if (response == null) throw new IllegalArgumentException("response is null");
4533 if (accountType == null) throw new IllegalArgumentException("accountType is null");
4534
4535 int userId = UserHandle.getCallingUserId();
4536
4537 long identityToken = clearCallingIdentity();
4538 try {
4539 UserAccounts userAccounts = getUserAccounts(userId);
4540 if (ArrayUtils.isEmpty(features)) {
4541 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4542 userAccounts, accountType, callingUid, opPackageName,
4543 true /* include managed not visible */);
4544 handleGetAccountsResult(
4545 response, accountsWithManagedNotVisible, opPackageName);
4546 return;
4547 }
4548
4549 IAccountManagerResponse retrieveAccountsResponse =
4550 new IAccountManagerResponse.Stub() {
4551 @Override
4552 public void onResult(Bundle value) throws RemoteException {
4553 Parcelable[] parcelables = value.getParcelableArray(
4554 AccountManager.KEY_ACCOUNTS);
4555 Account[] accounts = new Account[parcelables.length];
4556 for (int i = 0; i < parcelables.length; i++) {
4557 accounts[i] = (Account) parcelables[i];
4558 }
4559 handleGetAccountsResult(
4560 response, accounts, opPackageName);
4561 }
4562
4563 @Override
4564 public void onError(int errorCode, String errorMessage)
4565 throws RemoteException {
4566 // Will not be called in this case.
4567 }
4568 };
4569 new GetAccountsByTypeAndFeatureSession(
4570 userAccounts,
4571 retrieveAccountsResponse,
4572 accountType,
4573 features,
4574 callingUid,
4575 opPackageName,
4576 true /* include managed not visible */).bind();
4577 } finally {
4578 restoreCallingIdentity(identityToken);
4579 }
4580 }
4581
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004582 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004583 public void getAccountsByFeatures(
4584 IAccountManagerResponse response,
4585 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004586 String[] features,
4587 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004588 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004589 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004590 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4591 Log.v(TAG, "getAccounts: accountType " + type
4592 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004593 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004594 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004595 + ", pid " + Binder.getCallingPid());
4596 }
Fred Quintana382601f2010-03-25 12:25:10 -07004597 if (response == null) throw new IllegalArgumentException("response is null");
4598 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004599 int userId = UserHandle.getCallingUserId();
4600
Svetoslavf3f02ac2015-09-08 14:36:35 -07004601 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4602 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004603 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004604 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004605 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004606 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004607 try {
4608 response.onResult(result);
4609 } catch (RemoteException e) {
4610 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4611 }
4612 return;
4613 }
sunjianf29d5492017-05-11 15:42:31 -07004614
Fred Quintana33269202009-04-20 16:05:10 -07004615 long identityToken = clearCallingIdentity();
4616 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004617 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004618 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004619 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4620 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004621 Bundle result = new Bundle();
4622 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4623 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004624 return;
4625 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004626 new GetAccountsByTypeAndFeatureSession(
4627 userAccounts,
4628 response,
4629 type,
4630 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004631 callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004632 opPackageName,
4633 false /* include managed not visible */).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004634 } finally {
4635 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004636 }
4637 }
4638
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004639 @Override
4640 public void onAccountAccessed(String token) throws RemoteException {
4641 final int uid = Binder.getCallingUid();
4642 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4643 return;
4644 }
4645 final int userId = UserHandle.getCallingUserId();
4646 final long identity = Binder.clearCallingIdentity();
4647 try {
4648 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4649 if (Objects.equals(account.getAccessId(), token)) {
4650 // An app just accessed the account. At this point it knows about
4651 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004652 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004653 if (!hasAccountAccess(account, null, uid)) {
4654 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4655 uid, true);
4656 }
4657 }
4658 }
4659 } finally {
4660 Binder.restoreCallingIdentity(identity);
4661 }
4662 }
4663
Hongming Jin8e2bfc12018-05-30 11:01:06 -07004664 @Override
4665 public void onShellCommand(FileDescriptor in, FileDescriptor out,
4666 FileDescriptor err, String[] args, ShellCallback callback,
4667 ResultReceiver resultReceiver) {
4668 new AccountManagerServiceShellCommand(this).exec(this, in, out, err, args,
4669 callback, resultReceiver);
4670 }
4671
Fred Quintanaa698f422009-04-08 19:14:54 -07004672 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004673 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004674 IAccountManagerResponse mResponse;
4675 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004676 final boolean mExpectActivityLaunch;
4677 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004678 final String mAccountName;
4679 // Indicates if we need to add auth details(like last credential time)
4680 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004681 // If set, we need to update the last authenticated time. This is
4682 // currently
4683 // used on
4684 // successful confirming credentials.
4685 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004686
Fred Quintana33269202009-04-20 16:05:10 -07004687 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004688 private int mNumRequestContinued = 0;
4689 private int mNumErrors = 0;
4690
Fred Quintana60307342009-03-24 22:48:12 -07004691 IAccountAuthenticator mAuthenticator = null;
4692
Fred Quintana8570f742010-02-18 10:32:54 -08004693 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004694 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004695
Amith Yamasani04e0d262012-02-14 11:50:53 -08004696 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004697 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4698 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004699 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4700 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4701 }
4702
4703 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4704 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4705 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004706 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004707 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004708 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004709 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004710 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004711 mResponse = response;
4712 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004713 mExpectActivityLaunch = expectActivityLaunch;
4714 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004715 mAccountName = accountName;
4716 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004717 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004718
Fred Quintanaa698f422009-04-08 19:14:54 -07004719 synchronized (mSessions) {
4720 mSessions.put(toString(), this);
4721 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004722 if (response != null) {
4723 try {
4724 response.asBinder().linkToDeath(this, 0 /* flags */);
4725 } catch (RemoteException e) {
4726 mResponse = null;
4727 binderDied();
4728 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004729 }
Fred Quintana60307342009-03-24 22:48:12 -07004730 }
4731
Fred Quintanaa698f422009-04-08 19:14:54 -07004732 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004733 if (mResponse == null) {
4734 // this session has already been closed
4735 return null;
4736 }
Fred Quintana60307342009-03-24 22:48:12 -07004737 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004738 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004739 return response;
4740 }
4741
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004742 /**
4743 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4744 * security policy.
4745 *
4746 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004747 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004748 * supplied entries in the system Settings app.
4749 */
tiansiminga8868bf2017-09-20 13:59:13 +08004750 protected boolean checkKeyIntent(int authUid, Intent intent) {
Jeff Sharkeyd722e782017-06-12 17:33:07 -06004751 intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4752 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4753 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4754 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004755 long bid = Binder.clearCallingIdentity();
4756 try {
4757 PackageManager pm = mContext.getPackageManager();
4758 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
tiansiminga8868bf2017-09-20 13:59:13 +08004759 if (resolveInfo == null) {
4760 return false;
4761 }
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004762 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4763 int targetUid = targetActivityInfo.applicationInfo.uid;
Dan Cashman303c4bb2018-04-10 07:41:16 -07004764 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004765 if (!isExportedSystemActivity(targetActivityInfo)
Dan Cashman303c4bb2018-04-10 07:41:16 -07004766 && !pmi.hasSignatureCapability(
4767 targetUid, authUid,
4768 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004769 String pkgName = targetActivityInfo.packageName;
4770 String activityName = targetActivityInfo.name;
4771 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4772 + "does not share a signature with the supplying authenticator (%s).";
tiansiminga8868bf2017-09-20 13:59:13 +08004773 Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
4774 return false;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004775 }
tiansiminga8868bf2017-09-20 13:59:13 +08004776 return true;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004777 } finally {
4778 Binder.restoreCallingIdentity(bid);
4779 }
4780 }
4781
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004782 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4783 String className = activityInfo.name;
4784 return "android".equals(activityInfo.packageName) &&
4785 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4786 || CantAddAccountActivity.class.getName().equals(className));
4787 }
4788
Fred Quintanaa698f422009-04-08 19:14:54 -07004789 private void close() {
4790 synchronized (mSessions) {
4791 if (mSessions.remove(toString()) == null) {
4792 // the session was already closed, so bail out now
4793 return;
4794 }
4795 }
4796 if (mResponse != null) {
4797 // stop listening for response deaths
4798 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4799
4800 // clear this so that we don't accidentally send any further results
4801 mResponse = null;
4802 }
4803 cancelTimeout();
4804 unbind();
4805 }
4806
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004807 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004808 public void binderDied() {
4809 mResponse = null;
4810 close();
4811 }
4812
4813 protected String toDebugString() {
4814 return toDebugString(SystemClock.elapsedRealtime());
4815 }
4816
4817 protected String toDebugString(long now) {
4818 return "Session: expectLaunch " + mExpectActivityLaunch
4819 + ", connected " + (mAuthenticator != null)
4820 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4821 + "/" + mNumErrors + ")"
4822 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4823 }
4824
Fred Quintana60307342009-03-24 22:48:12 -07004825 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004826 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4827 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4828 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004829 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004830 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004831 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004832 }
4833 }
4834
4835 private void unbind() {
4836 if (mAuthenticator != null) {
4837 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004838 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004839 }
4840 }
4841
Fred Quintana60307342009-03-24 22:48:12 -07004842 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004843 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004844 }
4845
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004846 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004847 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004848 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004849 try {
4850 run();
4851 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004852 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004853 "remote exception");
4854 }
Fred Quintana60307342009-03-24 22:48:12 -07004855 }
4856
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004857 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004858 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004859 mAuthenticator = null;
4860 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004861 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004862 try {
4863 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4864 "disconnected");
4865 } catch (RemoteException e) {
4866 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4867 Log.v(TAG, "Session.onServiceDisconnected: "
4868 + "caught RemoteException while responding", e);
4869 }
4870 }
Fred Quintana60307342009-03-24 22:48:12 -07004871 }
4872 }
4873
Fred Quintanab839afc2009-10-14 15:57:28 -07004874 public abstract void run() throws RemoteException;
4875
Fred Quintana60307342009-03-24 22:48:12 -07004876 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004877 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004878 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004879 try {
4880 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4881 "timeout");
4882 } catch (RemoteException e) {
4883 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4884 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4885 e);
4886 }
4887 }
Fred Quintana60307342009-03-24 22:48:12 -07004888 }
4889 }
4890
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004891 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004892 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004893 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004894 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004895 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004896 if (result != null) {
4897 boolean isSuccessfulConfirmCreds = result.getBoolean(
4898 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004899 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004900 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4901 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004902 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004903 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4904 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004905 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004906 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004907 if (needUpdate || mAuthDetailsRequired) {
4908 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4909 if (needUpdate && accountPresent) {
4910 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4911 }
4912 if (mAuthDetailsRequired) {
4913 long lastAuthenticatedTime = -1;
4914 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004915 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004916 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004917 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004918 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004919 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004920 lastAuthenticatedTime);
4921 }
4922 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004923 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004924 if (result != null
4925 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08004926 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004927 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08004928 intent)) {
4929 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
4930 "invalid intent in bundle returned");
4931 return;
4932 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004933 }
4934 if (result != null
4935 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004936 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4937 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004938 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4939 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004940 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4941 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004942 }
Fred Quintana60307342009-03-24 22:48:12 -07004943 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004944 IAccountManagerResponse response;
4945 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004946 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004947 response = mResponse;
4948 } else {
4949 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004950 }
Fred Quintana60307342009-03-24 22:48:12 -07004951 if (response != null) {
4952 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004953 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004954 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4955 Log.v(TAG, getClass().getSimpleName()
4956 + " calling onError() on response " + response);
4957 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004958 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004959 "null bundle returned");
4960 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004961 if (mStripAuthTokenFromResult) {
4962 result.remove(AccountManager.KEY_AUTHTOKEN);
4963 }
Fred Quintana56285a62010-12-02 14:20:51 -08004964 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4965 Log.v(TAG, getClass().getSimpleName()
4966 + " calling onResult() on response " + response);
4967 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004968 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4969 (intent == null)) {
4970 // All AccountManager error codes are greater than 0
4971 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4972 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4973 } else {
4974 response.onResult(result);
4975 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004976 }
Fred Quintana60307342009-03-24 22:48:12 -07004977 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004978 // if the caller is dead then there is no one to care about remote exceptions
4979 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4980 Log.v(TAG, "failure while notifying response", e);
4981 }
Fred Quintana60307342009-03-24 22:48:12 -07004982 }
4983 }
4984 }
Fred Quintana60307342009-03-24 22:48:12 -07004985
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004986 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004987 public void onRequestContinued() {
4988 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004989 }
4990
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004991 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004992 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004993 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004994 IAccountManagerResponse response = getResponseAndClose();
4995 if (response != null) {
4996 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004997 Log.v(TAG, getClass().getSimpleName()
4998 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004999 }
5000 try {
5001 response.onError(errorCode, errorMessage);
5002 } catch (RemoteException e) {
5003 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5004 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
5005 }
5006 }
5007 } else {
5008 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5009 Log.v(TAG, "Session.onError: already closed");
5010 }
Fred Quintana60307342009-03-24 22:48:12 -07005011 }
5012 }
Fred Quintanab839afc2009-10-14 15:57:28 -07005013
5014 /**
5015 * find the component name for the authenticator and initiate a bind
5016 * if no authenticator or the bind fails then return false, otherwise return true
5017 */
5018 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005019 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
5020 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
5021 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07005022 if (authenticatorInfo == null) {
5023 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5024 Log.v(TAG, "there is no authenticator for " + authenticatorType
5025 + ", bailing out");
5026 }
5027 return false;
5028 }
5029
Jeff Sharkeyce18c812016-04-27 16:00:41 -06005030 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06005031 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07005032 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
5033 + " which isn't encryption aware");
5034 return false;
5035 }
5036
Fred Quintanab839afc2009-10-14 15:57:28 -07005037 Intent intent = new Intent();
5038 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
5039 intent.setComponent(authenticatorInfo.componentName);
5040 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5041 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
5042 }
Hongming Jin8e2bfc12018-05-30 11:01:06 -07005043 int flags = Context.BIND_AUTO_CREATE;
5044 if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
5045 flags |= Context.BIND_ALLOW_INSTANT;
5046 }
5047 if (!mContext.bindServiceAsUser(intent, this, flags, UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07005048 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5049 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
5050 }
5051 return false;
5052 }
5053
Fred Quintanab839afc2009-10-14 15:57:28 -07005054 return true;
5055 }
Fred Quintana60307342009-03-24 22:48:12 -07005056 }
5057
Svet Ganov5d09c992016-09-07 09:57:41 -07005058 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07005059 MessageHandler(Looper looper) {
5060 super(looper);
5061 }
Costin Manolache3348f142009-09-29 18:58:36 -07005062
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07005063 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005064 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07005065 switch (msg.what) {
5066 case MESSAGE_TIMED_OUT:
5067 Session session = (Session)msg.obj;
5068 session.onTimedOut();
5069 break;
5070
Amith Yamasani5be347b2013-03-31 17:44:31 -07005071 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00005072 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07005073 break;
5074
Fred Quintana60307342009-03-24 22:48:12 -07005075 default:
5076 throw new IllegalStateException("unhandled message: " + msg.what);
5077 }
5078 }
5079 }
5080
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005081 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005082 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005083 }
5084
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005085 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005086 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005087 }
5088
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005089 /*
5090 * This function receives an opened writable database.
5091 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005092 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005093 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005094 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005095 }
5096
5097 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005098 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005099 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005100 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005101 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005102
5103 class LogRecordTask implements Runnable {
5104 private final String action;
5105 private final String tableName;
5106 private final long accountId;
5107 private final UserAccounts userAccount;
5108 private final int callingUid;
5109 private final long userDebugDbInsertionPoint;
5110
5111 LogRecordTask(final String action,
5112 final String tableName,
5113 final long accountId,
5114 final UserAccounts userAccount,
5115 final int callingUid,
5116 final long userDebugDbInsertionPoint) {
5117 this.action = action;
5118 this.tableName = tableName;
5119 this.accountId = accountId;
5120 this.userAccount = userAccount;
5121 this.callingUid = callingUid;
5122 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5123 }
5124
Andrew Scullc7770d62017-05-22 17:49:58 +01005125 @Override
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005126 public void run() {
5127 SQLiteStatement logStatement = userAccount.statementForLogging;
5128 logStatement.bindLong(1, accountId);
5129 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005130 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005131 logStatement.bindLong(4, callingUid);
5132 logStatement.bindString(5, tableName);
5133 logStatement.bindLong(6, userDebugDbInsertionPoint);
Tetsutoki Shiozawabe2d96a2017-10-24 18:44:00 +09005134 try {
5135 logStatement.execute();
5136 } catch (IllegalStateException e) {
5137 // Guard against crash, DB can already be closed
5138 // since this statement is executed on a handler thread
5139 Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
5140 + " action=" + action + " tableName=" + tableName + " Error: " + e);
5141 } finally {
5142 logStatement.clearBindings();
5143 }
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005144 }
5145 }
5146
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005147 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5148 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005149 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005150 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005151 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005152 }
5153
5154 /*
5155 * This should only be called once to compile the sql statement for logging
5156 * and to find the insertion point.
5157 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005158 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
5159 userAccount.debugDbInsertionPoint = userAccount.accountsDb
5160 .calculateDebugTableInsertionPoint();
5161 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005162 }
5163
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005164 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07005165 return asBinder();
5166 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005167
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005168 /**
5169 * Searches array of arguments for the specified string
5170 * @param args array of argument strings
5171 * @param value value to search for
5172 * @return true if the value is contained in the array
5173 */
5174 private static boolean scanArgs(String[] args, String value) {
5175 if (args != null) {
5176 for (String arg : args) {
5177 if (value.equals(arg)) {
5178 return true;
5179 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005180 }
5181 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005182 return false;
5183 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005184
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005185 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005186 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005187 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005188 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005189 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07005190
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005191 final List<UserInfo> users = getUserManager().getUsers();
5192 for (UserInfo user : users) {
5193 ipw.println("User " + user + ":");
5194 ipw.increaseIndent();
5195 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5196 ipw.println();
5197 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08005198 }
5199 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005200
Amith Yamasani04e0d262012-02-14 11:50:53 -08005201 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5202 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005203 if (isCheckinRequest) {
5204 // This is a checkin request. *Only* upload the account types and the count of
5205 // each.
5206 synchronized (userAccounts.dbLock) {
5207 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5208 }
5209 } else {
5210 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5211 Process.SYSTEM_UID, null /* packageName */, false);
5212 fout.println("Accounts: " + accounts.length);
5213 for (Account account : accounts) {
Hui Yu139c2482018-08-10 15:37:51 -07005214 fout.println(" " + account.toSafeString());
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005215 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005216
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005217 // Add debug information.
5218 fout.println();
5219 synchronized (userAccounts.dbLock) {
5220 userAccounts.accountsDb.dumpDebugTable(fout);
5221 }
5222 fout.println();
5223 synchronized (mSessions) {
5224 final long now = SystemClock.elapsedRealtime();
5225 fout.println("Active Sessions: " + mSessions.size());
5226 for (Session session : mSessions.values()) {
5227 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005228 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005229 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005230
5231 fout.println();
5232 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Tony Mak6d14d772017-07-13 17:49:46 +08005233
5234 boolean isUserUnlocked;
5235 synchronized (mUsers) {
5236 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
5237 }
5238 // Following logs are printed only when user is unlocked.
5239 if (!isUserUnlocked) {
5240 return;
5241 }
5242 fout.println();
5243 synchronized (userAccounts.dbLock) {
5244 Map<Account, Map<String, Integer>> allVisibilityValues =
5245 userAccounts.accountsDb.findAllVisibilityValues();
5246 fout.println("Account visibility:");
5247 for (Account account : allVisibilityValues.keySet()) {
5248 fout.println(" " + account.name);
5249 Map<String, Integer> visibilities = allVisibilityValues.get(account);
5250 for (Entry<String, Integer> entry : visibilities.entrySet()) {
5251 fout.println(" " + entry.getKey() + ", " + entry.getValue());
5252 }
5253 }
5254 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005255 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005256 }
5257
Amith Yamasani04e0d262012-02-14 11:50:53 -08005258 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005259 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005260 long identityToken = clearCallingIdentity();
5261 try {
5262 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5263 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5264 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005265
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005266 if (intent.getComponent() != null &&
5267 GrantCredentialsPermissionActivity.class.getName().equals(
5268 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005269 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005270 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005271 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04005272 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5273 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005274
Fred Quintana33f889a2009-09-14 17:31:26 -07005275 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005276 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05005277 Notification n =
5278 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005279 .setWhen(0)
5280 .setSmallIcon(android.R.drawable.stat_sys_warning)
5281 .setColor(contextForUser.getColor(
5282 com.android.internal.R.color.system_notification_accent_color))
5283 .setContentTitle(String.format(notificationTitleFormat, account.name))
5284 .setContentText(message)
5285 .setContentIntent(PendingIntent.getActivityAsUser(
5286 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005287 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005288 .build();
Chris Wren717a8812017-03-31 15:34:39 -04005289 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005290 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005291 } finally {
5292 restoreCallingIdentity(identityToken);
5293 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005294 }
5295
Chris Wren717a8812017-03-31 15:34:39 -04005296 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005297 String packageName, int userId) {
5298 final long token = clearCallingIdentity();
5299 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005300 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005301 try {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005302 // The calling uid must match either the package or op package, so use an op
5303 // package that matches the cleared calling identity.
5304 notificationManager.enqueueNotificationWithTag(packageName, "android",
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04005305 id.mTag, id.mId, notification, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005306 } catch (RemoteException e) {
5307 /* ignore - local call */
5308 }
5309 } finally {
5310 Binder.restoreCallingIdentity(token);
5311 }
Fred Quintana56285a62010-12-02 14:20:51 -08005312 }
5313
Chris Wren717a8812017-03-31 15:34:39 -04005314 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005315 cancelNotification(id, mContext.getPackageName(), user);
5316 }
5317
Chris Wren717a8812017-03-31 15:34:39 -04005318 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005319 long identityToken = clearCallingIdentity();
5320 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005321 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04005322 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005323 } catch (RemoteException e) {
5324 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005325 } finally {
5326 restoreCallingIdentity(identityToken);
5327 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005328 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005329
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005330 private boolean isPermittedForPackage(String packageName, int uid, int userId,
5331 String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005332 final long identity = Binder.clearCallingIdentity();
5333 try {
5334 IPackageManager pm = ActivityThread.getPackageManager();
5335 for (String perm : permissions) {
5336 if (pm.checkPermission(perm, packageName, userId)
5337 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005338 // Checks runtime permission revocation.
5339 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005340 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005341 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5342 return true;
5343 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005344 }
5345 }
5346 } catch (RemoteException e) {
5347 /* ignore - local call */
5348 } finally {
5349 Binder.restoreCallingIdentity(identity);
5350 }
5351 return false;
5352 }
5353
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005354 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5355 for (String perm : permissions) {
5356 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5357 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5358 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5359 }
5360 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005361 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005362 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5363 return true;
5364 }
5365 }
5366 }
5367 return false;
5368 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005369
Amith Yamasani67df64b2012-12-14 12:09:36 -08005370 private int handleIncomingUser(int userId) {
5371 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005372 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005373 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5374 } catch (RemoteException re) {
5375 // Shouldn't happen, local.
5376 }
5377 return userId;
5378 }
5379
Christopher Tateccbf84f2013-05-08 15:25:41 -07005380 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005381 String[] packages;
5382 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005383 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005384 packages = mPackageManager.getPackagesForUid(callingUid);
sunjian9ae597b62017-08-14 15:45:04 -07005385 if (packages == null) {
5386 Log.d(TAG, "No packages for callingUid " + callingUid);
Fred Quintana7be59642009-08-24 18:29:25 -07005387 return false;
5388 }
sunjian9ae597b62017-08-14 15:45:04 -07005389 for (String name : packages) {
5390 try {
5391 PackageInfo packageInfo =
5392 mPackageManager.getPackageInfo(name, 0 /* flags */);
5393 if (packageInfo != null
5394 && (packageInfo.applicationInfo.privateFlags
5395 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
5396 return true;
5397 }
5398 } catch (PackageManager.NameNotFoundException e) {
5399 Log.d(TAG, "Package not found " + e.getMessage());
5400 }
5401 }
5402 } finally {
5403 Binder.restoreCallingIdentity(identityToken);
Fred Quintana7be59642009-08-24 18:29:25 -07005404 }
5405 return false;
5406 }
5407
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005408 private boolean permissionIsGranted(
5409 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005410 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5411 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5412 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5413 }
5414 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005415 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005416
5417 if (isPrivileged(callerUid)) {
5418 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5419 Log.v(TAG, "Access to " + account + " granted calling uid "
5420 + callerUid + " privileged");
5421 }
5422 return true;
5423 }
5424 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5425 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5426 Log.v(TAG, "Access to " + account + " granted calling uid "
5427 + callerUid + " manages the account");
5428 }
5429 return true;
5430 }
5431 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5432 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5433 Log.v(TAG, "Access to " + account + " granted calling uid "
5434 + callerUid + " user granted access");
5435 }
5436 return true;
5437 }
5438
5439 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5440 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5441 }
5442
5443 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005444 }
5445
Svetoslavf3f02ac2015-09-08 14:36:35 -07005446 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5447 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005448 if (accountType == null) {
5449 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005450 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005451 return getTypesVisibleToCaller(callingUid, userId,
5452 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005453 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005454 }
5455
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005456 // Method checks visibility for applications targeing API level below {@link
5457 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005458 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005459 private boolean checkGetAccountsPermission(String packageName, int uid, int userId) {
5460 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005461 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5462 }
5463
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005464 private boolean checkReadContactsPermission(String packageName, int uid, int userId) {
5465 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS);
5466 }
5467
5468 // Heuristic to check that account type may be associated with some contacts data and
5469 // therefore READ_CONTACTS permission grants the access to account by default.
5470 private boolean accountTypeManagesContacts(String accountType, int userId) {
5471 if (accountType == null) {
5472 return false;
5473 }
5474 long identityToken = Binder.clearCallingIdentity();
5475 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5476 try {
5477 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5478 } finally {
5479 Binder.restoreCallingIdentity(identityToken);
5480 }
5481 // Check contacts related permissions for authenticator.
5482 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5483 : serviceInfos) {
5484 if (accountType.equals(serviceInfo.type.type)) {
5485 return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId,
5486 Manifest.permission.WRITE_CONTACTS);
5487 }
5488 }
5489 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005490 }
5491
5492 /**
5493 * Method checks package uid and signature with Authenticator which manages accountType.
5494 *
5495 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5496 * SIGNATURE_CHECK_MISMATCH otherwise.
5497 */
5498 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5499 if (accountType == null) {
5500 return SIGNATURE_CHECK_MISMATCH;
5501 }
5502
5503 long identityToken = Binder.clearCallingIdentity();
5504 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5505 try {
5506 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5507 } finally {
5508 Binder.restoreCallingIdentity(identityToken);
5509 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005510 // Check for signature match with Authenticator.LocalServices.getService(PackageManagerInternal.class);
5511 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005512 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5513 : serviceInfos) {
5514 if (accountType.equals(serviceInfo.type.type)) {
5515 if (serviceInfo.uid == callingUid) {
5516 return SIGNATURE_CHECK_UID_MATCH;
5517 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005518 if (pmi.hasSignatureCapability(
5519 serviceInfo.uid, callingUid,
5520 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005521 return SIGNATURE_CHECK_MATCH;
5522 }
5523 }
5524 }
5525 return SIGNATURE_CHECK_MISMATCH;
5526 }
5527
5528 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005529 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5530 if (accountType == null) {
5531 return false;
5532 } else {
5533 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5534 }
5535 }
5536
Svetoslavf3f02ac2015-09-08 14:36:35 -07005537 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5538 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005539 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005540 }
5541
5542 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005543 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005544 }
5545
5546 private List<String> getTypesForCaller(
5547 int callingUid, int userId, boolean isOtherwisePermitted) {
5548 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005549 long identityToken = Binder.clearCallingIdentity();
5550 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5551 try {
5552 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5553 } finally {
5554 Binder.restoreCallingIdentity(identityToken);
5555 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005556
5557 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005558 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005559 serviceInfos) {
Dan Cashman303c4bb2018-04-10 07:41:16 -07005560 if (isOtherwisePermitted || pmi.hasSignatureCapability(
5561 serviceInfo.uid, callingUid,
5562 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005563 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005564 }
5565 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005566 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005567 }
5568
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005569 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5570 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5571 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5572 if (account.name.equals(accountName)) {
5573 return true;
5574 }
5575 }
5576 }
5577 return false;
5578 }
5579
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005580 private static void checkManageUsersPermission(String message) {
5581 if (ActivityManager.checkComponentPermission(
5582 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5583 != PackageManager.PERMISSION_GRANTED) {
5584 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5585 }
5586 }
5587
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005588 private static void checkManageOrCreateUsersPermission(String message) {
5589 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5590 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5591 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5592 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5593 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5594 + message);
5595 }
5596 }
5597
Amith Yamasani04e0d262012-02-14 11:50:53 -08005598 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5599 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005600 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005601 return true;
5602 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005603 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005604 synchronized (accounts.dbLock) {
5605 synchronized (accounts.cacheLock) {
5606 long grantsCount;
5607 if (authTokenType != null) {
5608 grantsCount = accounts.accountsDb
5609 .findMatchingGrantsCount(callerUid, authTokenType, account);
5610 } else {
5611 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5612 account);
5613 }
5614 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005615
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005616 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5617 // TODO: Skip this check when running automated tests. Replace this
5618 // with a more general solution.
Hui Yu139c2482018-08-10 15:37:51 -07005619 Log.d(TAG, "no credentials permission for usage of "
5620 + account.toSafeString() + ", "
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005621 + authTokenType + " by uid " + callerUid
5622 + " but ignoring since device is in test harness.");
5623 return true;
5624 }
5625 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005626 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005627 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005628 }
5629
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005630 private boolean isSystemUid(int callingUid) {
5631 String[] packages = null;
5632 long ident = Binder.clearCallingIdentity();
5633 try {
5634 packages = mPackageManager.getPackagesForUid(callingUid);
Alex Chau81a47cd2018-01-02 16:49:14 +00005635 if (packages != null) {
5636 for (String name : packages) {
5637 try {
5638 PackageInfo packageInfo =
5639 mPackageManager.getPackageInfo(name, 0 /* flags */);
5640 if (packageInfo != null
5641 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5642 != 0) {
5643 return true;
5644 }
5645 } catch (NameNotFoundException e) {
5646 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5647 }
5648 }
5649 } else {
5650 Log.w(TAG, "No known packages with uid " + callingUid);
5651 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005652 } finally {
5653 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005654 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005655 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005656 }
5657
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005658 /** Succeeds if any of the specified permissions are granted. */
5659 private void checkReadAccountsPermitted(
5660 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005661 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005662 int userId,
5663 String opPackageName) {
5664 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005665 String msg = String.format(
5666 "caller uid %s cannot access %s accounts",
5667 callingUid,
5668 accountType);
5669 Log.w(TAG, " " + msg);
5670 throw new SecurityException(msg);
5671 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005672 }
5673
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005674 private boolean canUserModifyAccounts(int userId, int callingUid) {
5675 // the managing app can always modify accounts
5676 if (isProfileOwner(callingUid)) {
5677 return true;
5678 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005679 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5680 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5681 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005682 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005683 return true;
5684 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005685
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005686 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5687 // the managing app can always modify accounts
5688 if (isProfileOwner(callingUid)) {
5689 return true;
5690 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005691 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5692 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005693 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005694 if (typesArray == null) {
5695 return true;
5696 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005697 for (String forbiddenType : typesArray) {
5698 if (forbiddenType.equals(accountType)) {
5699 return false;
5700 }
5701 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005702 return true;
5703 }
5704
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005705 private boolean isProfileOwner(int uid) {
5706 final DevicePolicyManagerInternal dpmi =
5707 LocalServices.getService(DevicePolicyManagerInternal.class);
5708 return (dpmi != null)
5709 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5710 }
5711
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005712 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005713 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5714 throws RemoteException {
5715 final int callingUid = getCallingUid();
5716
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005717 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005718 throw new SecurityException();
5719 }
5720
5721 if (value) {
5722 grantAppPermission(account, authTokenType, uid);
5723 } else {
5724 revokeAppPermission(account, authTokenType, uid);
5725 }
5726 }
5727
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005728 /**
5729 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5730 * <p>
5731 * Although this is public it can only be accessed via the AccountManagerService object
5732 * which is in the system. This means we don't need to protect it with permissions.
5733 * @hide
5734 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005735 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005736 if (account == null || authTokenType == null) {
5737 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005738 return;
5739 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005740 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005741 synchronized (accounts.dbLock) {
5742 synchronized (accounts.cacheLock) {
5743 long accountId = accounts.accountsDb.findDeAccountId(account);
5744 if (accountId >= 0) {
5745 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5746 }
5747 cancelNotification(
5748 getCredentialPermissionNotificationId(account, authTokenType, uid),
5749 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005750
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005751 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5752 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005753 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005754
5755 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5756 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5757 : mAppPermissionChangeListeners) {
5758 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5759 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005760 }
5761
5762 /**
5763 * Don't allow callers with the given uid permission to get credentials for
5764 * account/authTokenType.
5765 * <p>
5766 * Although this is public it can only be accessed via the AccountManagerService object
5767 * which is in the system. This means we don't need to protect it with permissions.
5768 * @hide
5769 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005770 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005771 if (account == null || authTokenType == null) {
5772 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005773 return;
5774 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005775 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005776 synchronized (accounts.dbLock) {
5777 synchronized (accounts.cacheLock) {
5778 accounts.accountsDb.beginTransaction();
5779 try {
5780 long accountId = accounts.accountsDb.findDeAccountId(account);
5781 if (accountId >= 0) {
5782 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5783 accountId, authTokenType, uid);
5784 accounts.accountsDb.setTransactionSuccessful();
5785 }
5786 } finally {
5787 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005788 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005789
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005790 cancelNotification(
5791 getCredentialPermissionNotificationId(account, authTokenType, uid),
5792 UserHandle.of(accounts.userId));
5793 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005794 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005795
5796 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5797 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5798 : mAppPermissionChangeListeners) {
5799 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5800 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005801 }
Fred Quintana56285a62010-12-02 14:20:51 -08005802
Amith Yamasani04e0d262012-02-14 11:50:53 -08005803 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5804 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005805 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005806 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005807 for (Account curAccount : oldAccountsForType) {
5808 if (!curAccount.equals(account)) {
5809 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005810 }
5811 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005812 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005813 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005814 } else {
5815 Account[] newAccountsForType = new Account[newAccountsList.size()];
5816 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005817 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005818 }
Fred Quintana56285a62010-12-02 14:20:51 -08005819 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005820 accounts.userDataCache.remove(account);
5821 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005822 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005823 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005824 }
5825
5826 /**
5827 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005828 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5829 * processes and if you will return this account to apps you should return the result.
5830 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005831 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005832 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005833 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005834 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5835 Account[] newAccountsForType = new Account[oldLength + 1];
5836 if (accountsForType != null) {
5837 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005838 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005839 String token = account.getAccessId() != null ? account.getAccessId()
5840 : UUID.randomUUID().toString();
5841 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005842 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005843 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005844 }
5845
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005846 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005847 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005848 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005849 String visibilityFilterPackage = callingPackage;
5850 if (visibilityFilterPackage == null) {
5851 visibilityFilterPackage = getPackageNameForUid(callingUid);
5852 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005853 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005854 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005855 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005856 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5857 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5858 || (includeManagedNotVisible
5859 && (visibility
5860 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5861 firstPass.put(account, visibility);
5862 }
5863 }
5864 Map<Account, Integer> secondPass =
5865 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5866
5867 Account[] filtered = new Account[secondPass.size()];
5868 filtered = secondPass.keySet().toArray(filtered);
5869 return filtered;
5870 }
5871
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005872 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005873 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005874 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005875 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005876 // first part is to filter shared accounts.
5877 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005878 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005879 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005880 return unfiltered;
5881 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005882 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005883 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005884 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005885 if (packages == null) {
5886 packages = new String[] {};
5887 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005888 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005889 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005890 // This might be a temporary way to specify a visible list
5891 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005892 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5893 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005894 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005895 return unfiltered;
5896 }
5897 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005898 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005899 if (ArrayUtils.isEmpty(sharedAccounts)) {
5900 return unfiltered;
5901 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005902 String requiredAccountType = "";
5903 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005904 // If there's an explicit callingPackage specified, check if that package
5905 // opted in to see restricted accounts.
5906 if (callingPackage != null) {
5907 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005908 if (pi != null && pi.restrictedAccountType != null) {
5909 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005910 }
5911 } else {
5912 // Otherwise check if the callingUid has a package that has opted in
5913 for (String packageName : packages) {
5914 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5915 if (pi != null && pi.restrictedAccountType != null) {
5916 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005917 break;
5918 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005919 }
5920 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005921 } catch (NameNotFoundException e) {
5922 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005923 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005924 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005925 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5926 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005927 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005928 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005929 } else {
5930 boolean found = false;
5931 for (Account shared : sharedAccounts) {
5932 if (shared.equals(account)) {
5933 found = true;
5934 break;
5935 }
5936 }
5937 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005938 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005939 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005940 }
5941 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005942 return filtered;
5943 } else {
5944 return unfiltered;
5945 }
5946 }
5947
Amith Yamasani27db4682013-03-30 17:07:47 -07005948 /*
5949 * packageName can be null. If not null, it should be used to filter out restricted accounts
5950 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005951 *
5952 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5953 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005954 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005955 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005956 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005957 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005958 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5959 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005960 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005961 Account[] accounts;
5962 synchronized (userAccounts.cacheLock) {
5963 accounts = userAccounts.accountCache.get(accountType);
5964 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005965 if (accounts == null) {
5966 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005967 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005968 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5969 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005970 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005971 } else {
5972 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005973 Account[] accountsArray;
5974 synchronized (userAccounts.cacheLock) {
5975 for (Account[] accounts : userAccounts.accountCache.values()) {
5976 totalLength += accounts.length;
5977 }
5978 if (totalLength == 0) {
5979 return EMPTY_ACCOUNT_ARRAY;
5980 }
5981 accountsArray = new Account[totalLength];
5982 totalLength = 0;
5983 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5984 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5985 accountsOfType.length);
5986 totalLength += accountsOfType.length;
5987 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005988 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005989 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005990 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005991 }
5992 }
5993
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005994 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005995 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005996 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005997 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005998 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005999 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08006000 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006001 }
6002 if (value == null) {
6003 userDataForAccount.remove(key);
6004 } else {
6005 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08006006 }
6007 }
6008
Carlos Valdivia91979be2015-05-22 14:11:35 -07006009 protected String readCachedTokenInternal(
6010 UserAccounts accounts,
6011 Account account,
6012 String tokenType,
6013 String callingPackage,
6014 byte[] pkgSigDigest) {
Dmitry Dementyev18f0ca92017-06-12 17:56:47 -07006015 synchronized (accounts.cacheLock) {
6016 return accounts.accountTokenCaches.get(
6017 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07006018 }
6019 }
6020
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006021 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006022 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08006023 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006024 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006025 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006026 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08006027 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006028 }
6029 if (value == null) {
6030 authTokensForAccount.remove(key);
6031 } else {
6032 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08006033 }
6034 }
6035
Amith Yamasani04e0d262012-02-14 11:50:53 -08006036 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
6037 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006038 // Fast path - check if account is already cached
6039 synchronized (accounts.cacheLock) {
6040 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6041 if (authTokensForAccount != null) {
6042 return authTokensForAccount.get(authTokenType);
6043 }
6044 }
6045 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07006046 synchronized (accounts.dbLock) {
6047 synchronized (accounts.cacheLock) {
6048 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6049 if (authTokensForAccount == null) {
6050 // need to populate the cache for this account
6051 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6052 accounts.authTokenCache.put(account, authTokensForAccount);
6053 }
6054 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08006055 }
Fred Quintana56285a62010-12-02 14:20:51 -08006056 }
6057 }
6058
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006059 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
6060 Map<String, String> userDataForAccount;
6061 // Fast path - check if data is already cached
6062 synchronized (accounts.cacheLock) {
6063 userDataForAccount = accounts.userDataCache.get(account);
6064 }
6065 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00006066 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006067 synchronized (accounts.dbLock) {
6068 synchronized (accounts.cacheLock) {
6069 userDataForAccount = accounts.userDataCache.get(account);
6070 if (userDataForAccount == null) {
6071 // need to populate the cache for this account
6072 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6073 accounts.userDataCache.put(account, userDataForAccount);
6074 }
6075 }
6076 }
Fred Quintana56285a62010-12-02 14:20:51 -08006077 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00006078 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08006079 }
6080
Kenny Guy07ad8dc2014-09-01 20:56:12 +01006081 private Context getContextForUser(UserHandle user) {
6082 try {
6083 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
6084 } catch (NameNotFoundException e) {
6085 // Default to mContext, not finding the package system is running as is unlikely.
6086 return mContext;
6087 }
6088 }
Sandra Kwan78812282015-11-04 11:19:47 -08006089
6090 private void sendResponse(IAccountManagerResponse response, Bundle result) {
6091 try {
6092 response.onResult(result);
6093 } catch (RemoteException e) {
6094 // if the caller is dead then there is no one to care about remote
6095 // exceptions
6096 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6097 Log.v(TAG, "failure while notifying response", e);
6098 }
6099 }
6100 }
6101
6102 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6103 String errorMessage) {
6104 try {
6105 response.onError(errorCode, errorMessage);
6106 } catch (RemoteException e) {
6107 // if the caller is dead then there is no one to care about remote
6108 // exceptions
6109 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6110 Log.v(TAG, "failure while notifying response", e);
6111 }
6112 }
6113 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006114
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006115 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07006116 private final Object mLock = new Object();
6117
6118 @GuardedBy("mLock")
6119 private AccountManagerBackupHelper mBackupHelper;
6120
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006121 @Override
6122 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6123 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6124 if (account == null) {
6125 Slog.w(TAG, "account cannot be null");
6126 return;
6127 }
6128 if (packageName == null) {
6129 Slog.w(TAG, "packageName cannot be null");
6130 return;
6131 }
6132 if (userId < UserHandle.USER_SYSTEM) {
6133 Slog.w(TAG, "user id must be concrete");
6134 return;
6135 }
6136 if (callback == null) {
6137 Slog.w(TAG, "callback cannot be null");
6138 return;
6139 }
6140
Dmitry Dementyev7b3ea132017-05-10 12:45:02 -07006141 int visibility =
6142 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6143 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6144 Slog.w(TAG, "requestAccountAccess: account is hidden");
6145 return;
6146 }
6147
Svet Ganovf6d424f12016-09-20 20:18:53 -07006148 if (AccountManagerService.this.hasAccountAccess(account, packageName,
6149 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006150 Bundle result = new Bundle();
6151 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6152 callback.sendResult(result);
6153 return;
6154 }
6155
6156 final int uid;
6157 try {
Dmitry Dementyev940b7602018-10-09 16:40:06 -07006158 long identityToken = clearCallingIdentity();
6159 try {
6160 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6161 } finally {
6162 restoreCallingIdentity(identityToken);
6163 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006164 } catch (NameNotFoundException e) {
6165 Slog.e(TAG, "Unknown package " + packageName);
6166 return;
6167 }
6168
6169 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006170 final UserAccounts userAccounts;
6171 synchronized (mUsers) {
6172 userAccounts = mUsers.get(userId);
6173 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04006174 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006175 doNotification(userAccounts, account, null, intent, packageName, userId);
6176 }
6177
6178 @Override
6179 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6180 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6181 mAppPermissionChangeListeners.add(listener);
6182 }
6183
6184 @Override
6185 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6186 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006187 }
Svet Ganov5d09c992016-09-07 09:57:41 -07006188
6189 @Override
6190 public byte[] backupAccountAccessPermissions(int userId) {
6191 synchronized (mLock) {
6192 if (mBackupHelper == null) {
6193 mBackupHelper = new AccountManagerBackupHelper(
6194 AccountManagerService.this, this);
6195 }
6196 return mBackupHelper.backupAccountAccessPermissions(userId);
6197 }
6198 }
6199
6200 @Override
6201 public void restoreAccountAccessPermissions(byte[] data, int userId) {
6202 synchronized (mLock) {
6203 if (mBackupHelper == null) {
6204 mBackupHelper = new AccountManagerBackupHelper(
6205 AccountManagerService.this, this);
6206 }
6207 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6208 }
6209 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006210 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07006211
6212 @VisibleForTesting
6213 static class Injector {
6214 private final Context mContext;
6215
6216 public Injector(Context context) {
6217 mContext = context;
6218 }
6219
6220 Looper getMessageHandlerLooper() {
6221 ServiceThread serviceThread = new ServiceThread(TAG,
6222 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6223 serviceThread.start();
6224 return serviceThread.getLooper();
6225 }
6226
6227 Context getContext() {
6228 return mContext;
6229 }
6230
6231 void addLocalService(AccountManagerInternal service) {
6232 LocalServices.addService(AccountManagerInternal.class, service);
6233 }
6234
6235 String getDeDatabaseName(int userId) {
6236 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6237 AccountsDb.DE_DATABASE_NAME);
6238 return databaseFile.getPath();
6239 }
6240
6241 String getCeDatabaseName(int userId) {
6242 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6243 AccountsDb.CE_DATABASE_NAME);
6244 return databaseFile.getPath();
6245 }
6246
6247 String getPreNDatabaseName(int userId) {
6248 File systemDir = Environment.getDataSystemDirectory();
6249 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6250 PRE_N_DATABASE_NAME);
6251 if (userId == 0) {
6252 // Migrate old file, if it exists, to the new location.
6253 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006254 // accidentally created in the old location,
6255 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07006256 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6257 if (oldFile.exists() && !databaseFile.exists()) {
6258 // Check for use directory; create if it doesn't exist, else renameTo will fail
6259 File userDir = Environment.getUserSystemDirectory(userId);
6260 if (!userDir.exists()) {
6261 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006262 throw new IllegalStateException(
6263 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006264 }
6265 }
6266 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006267 throw new IllegalStateException(
6268 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006269 }
6270 }
6271 }
6272 return databaseFile.getPath();
6273 }
6274
6275 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6276 return new AccountAuthenticatorCache(mContext);
6277 }
6278
6279 INotificationManager getNotificationManager() {
6280 return NotificationManager.getService();
6281 }
6282 }
Chris Wren717a8812017-03-31 15:34:39 -04006283
Andrew Scullc7770d62017-05-22 17:49:58 +01006284 private static class NotificationId {
Chris Wren717a8812017-03-31 15:34:39 -04006285 final String mTag;
6286 private final int mId;
6287
6288 NotificationId(String tag, int type) {
6289 mTag = tag;
6290 mId = type;
6291 }
6292 }
Fred Quintana60307342009-03-24 22:48:12 -07006293}