blob: c826df06c925e550eaaf1d49e88153ef27dd1d22 [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
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700244 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800245 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700246 synchronized (dbLock) {
247 synchronized (cacheLock) {
248 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
249 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800250 }
251 }
252 }
253
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700254 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600255 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700256 // Not thread-safe. Only use in synchronized context
257 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700258 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
259 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800260
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700261 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700262 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700263
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700264 /**
265 * This should only be called by system code. One should only call this after the service
266 * has started.
267 * @return a reference to the AccountManagerService instance
268 * @hide
269 */
270 public static AccountManagerService getSingleton() {
271 return sThis.get();
272 }
Fred Quintana60307342009-03-24 22:48:12 -0700273
Fyodor Kupolovda993802016-09-21 14:47:10 -0700274 public AccountManagerService(Injector injector) {
275 mInjector = injector;
276 mContext = injector.getContext();
277 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700278 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700279 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
280 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800281 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700282
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700283 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800284
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800285 IntentFilter intentFilter = new IntentFilter();
286 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
287 intentFilter.addDataScheme("package");
288 mContext.registerReceiver(new BroadcastReceiver() {
289 @Override
290 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700291 // Don't delete accounts when updating a authenticator's
292 // package.
293 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700294 /* Purging data requires file io, don't block the main thread. This is probably
295 * less than ideal because we are introducing a race condition where old grants
296 * could be exercised until they are purged. But that race condition existed
297 * anyway with the broadcast receiver.
298 *
299 * Ideally, we would completely clear the cache, purge data from the database,
300 * and then rebuild the cache. All under the cache lock. But that change is too
301 * large at this point.
302 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800303 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700304 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700305 @Override
306 public void run() {
307 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800308 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800309 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700310 }
311 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700312 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700313 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800314 }
315 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800316
Fyodor Kupolovda993802016-09-21 14:47:10 -0700317 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700318
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700319 IntentFilter userFilter = new IntentFilter();
320 userFilter.addAction(Intent.ACTION_USER_REMOVED);
321 mContext.registerReceiverAsUser(new BroadcastReceiver() {
322 @Override
323 public void onReceive(Context context, Intent intent) {
324 String action = intent.getAction();
325 if (Intent.ACTION_USER_REMOVED.equals(action)) {
326 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
327 if (userId < 1) return;
328 Slog.i(TAG, "User " + userId + " removed");
329 purgeUserData(userId);
330 }
331 }
332 }, UserHandle.ALL, userFilter, null, null);
333
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700334 // Need to cancel account request notifications if the update/install can access the account
335 new PackageMonitor() {
336 @Override
337 public void onPackageAdded(String packageName, int uid) {
338 // Called on a handler, and running as the system
339 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
340 }
341
342 @Override
343 public void onPackageUpdateFinished(String packageName, int uid) {
344 // Called on a handler, and running as the system
345 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
346 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700347 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700348
349 // Cancel account request notification if an app op was preventing the account access
350 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
351 new AppOpsManager.OnOpChangedInternalListener() {
352 @Override
353 public void onOpChanged(int op, String packageName) {
354 try {
355 final int userId = ActivityManager.getCurrentUser();
356 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
357 final int mode = mAppOpsManager.checkOpNoThrow(
358 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
359 if (mode == AppOpsManager.MODE_ALLOWED) {
360 final long identity = Binder.clearCallingIdentity();
361 try {
362 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
363 } finally {
364 Binder.restoreCallingIdentity(identity);
365 }
366 }
367 } catch (NameNotFoundException e) {
368 /* ignore */
369 }
370 }
371 });
372
373 // Cancel account request notification if a permission was preventing the account access
374 mPackageManager.addOnPermissionsChangeListener(
375 (int uid) -> {
376 Account[] accounts = null;
377 String[] packageNames = mPackageManager.getPackagesForUid(uid);
378 if (packageNames != null) {
379 final int userId = UserHandle.getUserId(uid);
380 final long identity = Binder.clearCallingIdentity();
381 try {
382 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800383 // if app asked for permission we need to cancel notification even
384 // for O+ applications.
385 if (mPackageManager.checkPermission(
386 Manifest.permission.GET_ACCOUNTS,
387 packageName) != PackageManager.PERMISSION_GRANTED) {
388 continue;
389 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700390
391 if (accounts == null) {
392 accounts = getAccountsAsUser(null, userId, "android");
393 if (ArrayUtils.isEmpty(accounts)) {
394 return;
395 }
396 }
397
398 for (Account account : accounts) {
399 cancelAccountAccessRequestNotificationIfNeeded(
400 account, uid, packageName, true);
401 }
402 }
403 } finally {
404 Binder.restoreCallingIdentity(identity);
405 }
406 }
407 });
408 }
409
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700410
411 boolean getBindInstantServiceAllowed(int userId) {
412 return mAuthenticatorCache.getBindInstantServiceAllowed(userId);
413 }
414
415 void setBindInstantServiceAllowed(int userId, boolean allowed) {
416 mAuthenticatorCache.setBindInstantServiceAllowed(userId, allowed);
417 }
418
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700419 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
420 boolean checkAccess) {
421 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
422 for (Account account : accounts) {
423 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
424 }
425 }
426
427 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
428 boolean checkAccess) {
429 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
430 for (Account account : accounts) {
431 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
432 }
433 }
434
435 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
436 boolean checkAccess) {
437 String[] packageNames = mPackageManager.getPackagesForUid(uid);
438 if (packageNames != null) {
439 for (String packageName : packageNames) {
440 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
441 packageName, checkAccess);
442 }
443 }
444 }
445
446 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
447 int uid, String packageName, boolean checkAccess) {
448 if (!checkAccess || hasAccountAccess(account, packageName,
449 UserHandle.getUserHandleForUid(uid))) {
450 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700451 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700452 UserHandle.getUserHandleForUid(uid));
453 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800454 }
455
Dianne Hackborn164371f2013-10-01 19:10:13 -0700456 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800457 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800458 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800459 Bundle.setDefusable(extras, true);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700460 int callingUid = Binder.getCallingUid();
461 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800462 if (Log.isLoggable(TAG, Log.VERBOSE)) {
463 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
464 + ", pid " + Binder.getCallingPid());
465 }
466 Preconditions.checkNotNull(account, "account cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800467 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
468 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
469 callingUid, account.type);
470 throw new SecurityException(msg);
471 }
472 /*
473 * Child users are not allowed to add accounts. Only the accounts that are shared by the
474 * parent profile can be added to child profile.
475 *
476 * TODO: Only allow accounts that were shared to be added by a limited user.
477 */
478 // fails if the account already exists
479 long identityToken = clearCallingIdentity();
480 try {
481 UserAccounts accounts = getUserAccounts(userId);
482 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800483 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800484 } finally {
485 restoreCallingIdentity(identityToken);
486 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700487 }
488
489 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800490 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
491 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800492 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700493 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800494 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700495 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800496
497 if ((accountType != null && !managedTypes.contains(accountType))
498 || (accountType == null && !isSystemUid)) {
499 throw new SecurityException(
500 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
501 + callingUid + " with packageName=" + packageName);
502 }
503 if (accountType != null) {
504 managedTypes = new ArrayList<String>();
505 managedTypes.add(accountType);
506 }
507
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800508 long identityToken = clearCallingIdentity();
509 try {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700510 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800511 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700512 accounts);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800513 } finally {
514 restoreCallingIdentity(identityToken);
515 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800516 }
517
518 /*
519 * accountTypes may not be null
520 */
521 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
522 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700523 if (!packageExistsForUser(packageName, accounts.userId)) {
524 Log.d(TAG, "Package not found " + packageName);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800525 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800526 }
527
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800528 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800529 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700530 synchronized (accounts.dbLock) {
531 synchronized (accounts.cacheLock) {
532 final Account[] accountsOfType = accounts.accountCache.get(accountType);
533 if (accountsOfType != null) {
534 for (Account account : accountsOfType) {
535 result.put(account,
536 resolveAccountVisibility(account, packageName, accounts));
537 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800538 }
539 }
540 }
541 }
542 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800543 }
544
545 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800546 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700547 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700548 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700549 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800550 if (!isAccountManagedByCaller(account.type, callingUid, userId)
551 && !isSystemUid(callingUid)) {
552 String msg =
553 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700554 throw new SecurityException(msg);
555 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700556
557 long identityToken = clearCallingIdentity();
558 try {
559 UserAccounts accounts = getUserAccounts(userId);
560 synchronized (accounts.dbLock) {
561 synchronized (accounts.cacheLock) {
562 return getPackagesAndVisibilityForAccountLocked(account, accounts);
563 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700564 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700565 } finally {
566 restoreCallingIdentity(identityToken);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700567 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700568
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800569 }
570
571 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700572 * Returns Map with all package names and visibility values for given account.
573 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800574 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800575 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800576 * @param accounts UserAccount that currently hosts the account and application
577 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700578 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800579 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700580 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800581 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700582 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
583 if (accountVisibility == null) {
584 Log.d(TAG, "Visibility was not initialized");
585 accountVisibility = new HashMap<>();
586 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800587 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700588 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700589 }
590
591 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700592 public int getAccountVisibility(Account account, String packageName) {
593 Preconditions.checkNotNull(account, "account cannot be null");
594 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800595 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700596 int userId = UserHandle.getCallingUserId();
597 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800598 && !isSystemUid(callingUid)) {
599 String msg = String.format(
600 "uid %s cannot get secrets for accounts of type: %s",
601 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700602 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800603 throw new SecurityException(msg);
604 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700605 long identityToken = clearCallingIdentity();
606 try {
607 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyevcbe1bd12017-04-25 17:02:47 -0700608 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
609 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
610 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
611 return visibility;
612 } else {
613 return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
614 }
615 }
616 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) {
617 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
618 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
619 return visibility;
620 } else {
621 return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
622 }
623 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700624 return resolveAccountVisibility(account, packageName, accounts);
625 } finally {
626 restoreCallingIdentity(identityToken);
627 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800628 }
629
630 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800631 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800632 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800633 * @param account The account to check visibility.
634 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800635 * @param accounts UserAccount that currently hosts the account and application
636 *
637 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
638 *
639 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700640 private int getAccountVisibilityFromCache(Account account, String packageName,
641 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700642 synchronized (accounts.cacheLock) {
643 Map<String, Integer> accountVisibility =
644 getPackagesAndVisibilityForAccountLocked(account, accounts);
645 Integer visibility = accountVisibility.get(packageName);
646 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800647 }
648 }
649
650 /**
651 * Method which handles default values for Account visibility.
652 *
653 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800654 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800655 * @param accounts UserAccount that currently hosts the account and application
656 *
657 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
658 *
659 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800660 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800661 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800662 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800663 int uid = -1;
664 try {
665 long identityToken = clearCallingIdentity();
666 try {
667 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
668 } finally {
669 restoreCallingIdentity(identityToken);
670 }
671 } catch (NameNotFoundException e) {
672 Log.d(TAG, "Package not found " + e.getMessage());
673 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800674 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800675
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800676 // System visibility can not be restricted.
677 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
678 return AccountManager.VISIBILITY_VISIBLE;
679 }
680
681 int signatureCheckResult =
682 checkPackageSignature(account.type, uid, accounts.userId);
683
684 // Authenticator can not restrict visibility to itself.
685 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
686 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
687 }
688
689 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700690 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800691
692 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
693 return visibility;
694 }
695
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700696 boolean isPrivileged = isPermittedForPackage(packageName, uid, accounts.userId,
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800697 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
698
699 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800700 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800701 return AccountManager.VISIBILITY_VISIBLE;
702 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800703
704 boolean preO = isPreOApplication(packageName);
705 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700706 || (preO && checkGetAccountsPermission(packageName, uid, accounts.userId))
707 || (checkReadContactsPermission(packageName, uid, accounts.userId)
708 && accountTypeManagesContacts(account.type, accounts.userId))
709 || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800710 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
711 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700712 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800713 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800714 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
715 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
716 }
717 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700718 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800719 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800720 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
721 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
722 }
723 }
724 return visibility;
725 }
726
727 /**
728 * Checks targetSdk for a package;
729 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800730 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800731 *
732 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
733 * undefined
734 */
735 private boolean isPreOApplication(String packageName) {
736 try {
737 long identityToken = clearCallingIdentity();
738 ApplicationInfo applicationInfo;
739 try {
740 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
741 } finally {
742 restoreCallingIdentity(identityToken);
743 }
744
745 if (applicationInfo != null) {
746 int version = applicationInfo.targetSdkVersion;
747 return version < android.os.Build.VERSION_CODES.O;
748 }
749 return true;
750 } catch (NameNotFoundException e) {
751 Log.d(TAG, "Package not found " + e.getMessage());
752 return true;
753 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800754 }
755
756 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700757 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
758 Preconditions.checkNotNull(account, "account cannot be null");
759 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800760 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700761 int userId = UserHandle.getCallingUserId();
762 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800763 && !isSystemUid(callingUid)) {
764 String msg = String.format(
765 "uid %s cannot get secrets for accounts of type: %s",
766 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700767 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800768 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700769 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700770 long identityToken = clearCallingIdentity();
771 try {
772 UserAccounts accounts = getUserAccounts(userId);
773 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700774 accounts);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700775 } finally {
776 restoreCallingIdentity(identityToken);
777 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700778 }
779
sunjian066aa5e2017-06-05 12:16:59 -0700780 private boolean isVisible(int visibility) {
781 return visibility == AccountManager.VISIBILITY_VISIBLE ||
782 visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
783 }
784
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700785 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800786 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700787 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800788 * @param account Account to update visibility.
789 * @param packageName Package name for which visibility is updated.
790 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800791 * @param notify if the flag is set applications will get notification about visibility change
792 * @param accounts UserAccount that currently hosts the account and application
793 *
794 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700795 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800796 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800797 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700798 synchronized (accounts.dbLock) {
799 synchronized (accounts.cacheLock) {
800 Map<String, Integer> packagesToVisibility;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700801 List<String> accountRemovedReceivers;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700802 if (notify) {
803 if (isSpecialPackageKey(packageName)) {
804 packagesToVisibility =
805 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700806 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700807 } else {
808 if (!packageExistsForUser(packageName, accounts.userId)) {
809 return false; // package is not installed.
810 }
811 packagesToVisibility = new HashMap<>();
812 packagesToVisibility.put(packageName,
813 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700814 accountRemovedReceivers = new ArrayList<>();
815 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
816 accountRemovedReceivers.add(packageName);
817 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700818 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800819 } else {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700820 // Notifications will not be send - only used during add account.
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700821 if (!isSpecialPackageKey(packageName) &&
822 !packageExistsForUser(packageName, accounts.userId)) {
823 // package is not installed and not meta value.
824 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100825 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700826 packagesToVisibility = Collections.emptyMap();
827 accountRemovedReceivers = Collections.emptyList();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800828 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700829
830 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800831 return false;
832 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800833
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700834 if (notify) {
835 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
836 .entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -0700837 int oldVisibility = packageToVisibility.getValue();
838 int currentVisibility =
839 resolveAccountVisibility(account, packageName, accounts);
840 if (isVisible(oldVisibility) != isVisible(currentVisibility)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700841 notifyPackage(packageToVisibility.getKey(), accounts);
842 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700843 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700844 for (String packageNameToNotify : accountRemovedReceivers) {
845 sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
846 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700847 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700848 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700849 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800850 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700851 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700852 }
853
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700854 // Update account visibility in cache and database.
855 private boolean updateAccountVisibilityLocked(Account account, String packageName,
856 int newVisibility, UserAccounts accounts) {
857 final long accountId = accounts.accountsDb.findDeAccountId(account);
858 if (accountId < 0) {
859 return false;
860 }
861
862 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
863 try {
864 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
865 newVisibility)) {
866 return false;
867 }
868 } finally {
869 StrictMode.setThreadPolicy(oldPolicy);
870 }
871 Map<String, Integer> accountVisibility =
872 getPackagesAndVisibilityForAccountLocked(account, accounts);
873 accountVisibility.put(packageName, newVisibility);
874 return true;
875 }
876
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700877 @Override
878 public void registerAccountListener(String[] accountTypes, String opPackageName) {
879 int callingUid = Binder.getCallingUid();
880 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700881
882 int userId = UserHandle.getCallingUserId();
883 long identityToken = clearCallingIdentity();
884 try {
885 UserAccounts accounts = getUserAccounts(userId);
886 registerAccountListener(accountTypes, opPackageName, accounts);
887 } finally {
888 restoreCallingIdentity(identityToken);
889 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800890 }
891
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700892 private void registerAccountListener(String[] accountTypes, String opPackageName,
893 UserAccounts accounts) {
894 synchronized (accounts.mReceiversForType) {
895 if (accountTypes == null) {
896 // null for any type
897 accountTypes = new String[] {null};
898 }
899 for (String type : accountTypes) {
900 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
901 if (receivers == null) {
902 receivers = new HashMap<>();
903 accounts.mReceiversForType.put(type, receivers);
904 }
905 Integer cnt = receivers.get(opPackageName);
906 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800907 }
908 }
909 }
910
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700911 @Override
912 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
913 int callingUid = Binder.getCallingUid();
914 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700915 int userId = UserHandle.getCallingUserId();
916 long identityToken = clearCallingIdentity();
917 try {
918 UserAccounts accounts = getUserAccounts(userId);
919 unregisterAccountListener(accountTypes, opPackageName, accounts);
920 } finally {
921 restoreCallingIdentity(identityToken);
922 }
923 }
924
925 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
926 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700927 synchronized (accounts.mReceiversForType) {
928 if (accountTypes == null) {
929 // null for any type
930 accountTypes = new String[] {null};
931 }
932 for (String type : accountTypes) {
933 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
934 if (receivers == null || receivers.get(opPackageName) == null) {
935 throw new IllegalArgumentException("attempt to unregister wrong receiver");
936 }
937 Integer cnt = receivers.get(opPackageName);
938 if (cnt == 1) {
939 receivers.remove(opPackageName);
940 } else {
941 receivers.put(opPackageName, cnt - 1);
942 }
943 }
944 }
945 }
946
947 // Send notification to all packages which can potentially see the account
948 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
949 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700950
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700951 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700952 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
953 && (packageToVisibility.getValue()
954 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700955 notifyPackage(packageToVisibility.getKey(), accounts);
956 }
957 }
958 }
959
960 /**
961 * Sends a direct intent to a package, notifying it of account visibility change.
962 *
963 * @param packageName to send Account to
964 * @param accounts UserAccount that currently hosts the account
965 */
966 private void notifyPackage(String packageName, UserAccounts accounts) {
967 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
968 intent.setPackage(packageName);
969 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
970 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
971 }
972
973 // Returns a map from package name to visibility, for packages subscribed
974 // to notifications about any account type, or type of provided account
975 // account type or all types.
976 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
977 Set<String> packages = new HashSet<>();
978 synchronized (accounts.mReceiversForType) {
979 for (String type : new String[] {account.type, null}) {
980 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
981 if (receivers != null) {
982 packages.addAll(receivers.keySet());
983 }
984 }
985 }
986 Map<String, Integer> result = new HashMap<>();
987 for (String packageName : packages) {
988 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
989 }
990 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800991 }
992
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700993 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
994 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
995 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
996 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
997 List<ResolveInfo> receivers =
998 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
999 List<String> result = new ArrayList<>();
1000 if (receivers == null) {
1001 return result;
1002 }
1003 for (ResolveInfo resolveInfo: receivers) {
1004 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
1005 int visibility = resolveAccountVisibility(account, packageName, accounts);
1006 if (visibility == AccountManager.VISIBILITY_VISIBLE
1007 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1008 result.add(packageName);
1009 }
1010 }
1011 return result;
1012 }
1013
1014 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
1015 private boolean shouldNotifyPackageOnAccountRemoval(Account account,
1016 String packageName, UserAccounts accounts) {
1017 int visibility = resolveAccountVisibility(account, packageName, accounts);
1018 if (visibility != AccountManager.VISIBILITY_VISIBLE
1019 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1020 return false;
1021 }
1022
1023 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1024 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1025 intent.setPackage(packageName);
1026 List<ResolveInfo> receivers =
1027 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1028 return (receivers != null && receivers.size() > 0);
1029 }
1030
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001031 private boolean packageExistsForUser(String packageName, int userId) {
1032 try {
1033 long identityToken = clearCallingIdentity();
1034 try {
1035 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -07001036 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001037 } finally {
1038 restoreCallingIdentity(identityToken);
1039 }
1040 } catch (NameNotFoundException e) {
1041 return false;
1042 }
1043 }
1044
1045 /**
1046 * Returns true if packageName is one of special values.
1047 */
1048 private boolean isSpecialPackageKey(String packageName) {
1049 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1050 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1051 }
1052
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001053 private void sendAccountsChangedBroadcast(int userId) {
1054 Log.i(TAG, "the accounts changed, sending broadcast of "
1055 + ACCOUNTS_CHANGED_INTENT.getAction());
1056 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001057 }
1058
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001059 private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001060 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1061 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001062 intent.setPackage(packageName);
1063 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1064 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001065 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1066 }
1067
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001068 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -07001069 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1070 throws RemoteException {
1071 try {
1072 return super.onTransact(code, data, reply, flags);
1073 } catch (RuntimeException e) {
1074 // The account manager only throws security exceptions, so let's
1075 // log all others.
1076 if (!(e instanceof SecurityException)) {
1077 Slog.wtf(TAG, "Account Manager Crash", e);
1078 }
1079 throw e;
1080 }
1081 }
1082
Amith Yamasani258848d2012-08-10 17:06:33 -07001083 private UserManager getUserManager() {
1084 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -07001085 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -07001086 }
1087 return mUserManager;
1088 }
1089
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001090 /**
1091 * Validate internal set of accounts against installed authenticators for
1092 * given user. Clears cached authenticators before validating.
1093 */
1094 public void validateAccounts(int userId) {
1095 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001096 // Invalidate user-specific cache to make sure we catch any
1097 // removed authenticators.
1098 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1099 }
1100
1101 /**
1102 * Validate internal set of accounts against installed authenticators for
1103 * given user. Clear cached authenticators before validating when requested.
1104 */
1105 private void validateAccountsInternal(
1106 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001107 if (Log.isLoggable(TAG, Log.DEBUG)) {
1108 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001109 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001110 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001111 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001112
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001113 if (invalidateAuthenticatorCache) {
1114 mAuthenticatorCache.invalidateCache(accounts.userId);
1115 }
1116
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001117 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1118 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001119 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001120
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001121 synchronized (accounts.dbLock) {
1122 synchronized (accounts.cacheLock) {
1123 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001124
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001125 // Get a map of stored authenticator types to UID
1126 final AccountsDb accountsDb = accounts.accountsDb;
1127 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1128 // Create a list of authenticator type whose previous uid no longer exists
1129 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1130 SparseBooleanArray knownUids = null;
1131 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1132 String type = authToUidEntry.getKey();
1133 int uid = authToUidEntry.getValue();
1134 Integer knownUid = knownAuth.get(type);
1135 if (knownUid != null && uid == knownUid) {
1136 // Remove it from the knownAuth list if it's unchanged.
1137 knownAuth.remove(type);
1138 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001139 /*
1140 * The authenticator is presently not cached and should only be triggered
1141 * when we think an authenticator has been removed (or is being updated).
1142 * But we still want to check if any data with the associated uid is
1143 * around. This is an (imperfect) signal that the package may be updating.
1144 *
1145 * A side effect of this is that an authenticator sharing a uid with
1146 * multiple apps won't get its credentials wiped as long as some app with
1147 * that uid is still on the device. But I suspect that this is a rare case.
1148 * And it isn't clear to me how an attacker could really exploit that
1149 * feature.
1150 *
1151 * The upshot is that we don't have to worry about accounts getting
1152 * uninstalled while the authenticator's package is being updated.
1153 *
1154 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001155 if (knownUids == null) {
1156 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1157 }
1158 if (!knownUids.get(uid)) {
1159 // The authenticator is not presently available to the cache. And the
1160 // package no longer has a data directory (so we surmise it isn't
1161 // updating). So purge its data from the account databases.
1162 obsoleteAuthType.add(type);
1163 // And delete it from the TABLE_META
1164 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1165 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001166 }
1167 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001168
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001169 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1170 // been re-enabled (after being updated for example), then we just overwrite the old
1171 // values.
1172 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1173 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1174 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001175
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001176 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1177 try {
1178 accounts.accountCache.clear();
1179 final HashMap<String, ArrayList<String>> accountNamesByType
1180 = new LinkedHashMap<>();
1181 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1182 final long accountId = accountEntry.getKey();
1183 final Account account = accountEntry.getValue();
1184 if (obsoleteAuthType.contains(account.type)) {
Hui Yu139c2482018-08-10 15:37:51 -07001185 Slog.w(TAG, "deleting account " + account.toSafeString()
1186 + " because type " + account.type
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001187 + "'s registered authenticator no longer exist.");
1188 Map<String, Integer> packagesToVisibility =
1189 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001190 List<String> accountRemovedReceivers =
1191 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001192 accountsDb.beginTransaction();
1193 try {
1194 accountsDb.deleteDeAccount(accountId);
1195 // Also delete from CE table if user is unlocked; if user is
1196 // currently locked the account will be removed later by
1197 // syncDeCeAccountsLocked
1198 if (userUnlocked) {
1199 accountsDb.deleteCeAccount(accountId);
1200 }
1201 accountsDb.setTransactionSuccessful();
1202 } finally {
1203 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001204 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001205 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001206
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001207 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1208 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001209
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001210 accounts.userDataCache.remove(account);
1211 accounts.authTokenCache.remove(account);
1212 accounts.accountTokenCaches.remove(account);
1213 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001214
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001215 for (Entry<String, Integer> packageToVisibility :
1216 packagesToVisibility.entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -07001217 if (isVisible(packageToVisibility.getValue())) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001218 notifyPackage(packageToVisibility.getKey(), accounts);
1219 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001220 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001221 for (String packageName : accountRemovedReceivers) {
1222 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1223 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001224 } else {
1225 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1226 if (accountNames == null) {
1227 accountNames = new ArrayList<>();
1228 accountNamesByType.put(account.type, accountNames);
1229 }
1230 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001231 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001232 }
1233 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1234 final String accountType = cur.getKey();
1235 final ArrayList<String> accountNames = cur.getValue();
1236 final Account[] accountsForType = new Account[accountNames.size()];
1237 for (int i = 0; i < accountsForType.length; i++) {
1238 accountsForType[i] = new Account(accountNames.get(i), accountType,
1239 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001240 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001241 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001242 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001243 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1244 } finally {
1245 if (accountDeleted) {
1246 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001247 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001248 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001249 }
1250 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001251 }
1252
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001253 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1254 // Get the UIDs of all apps that might have data on the device. We want
1255 // to preserve user data if the app might otherwise be storing data.
1256 List<PackageInfo> pkgsWithData =
1257 mPackageManager.getInstalledPackagesAsUser(
1258 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1259 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1260 for (PackageInfo pkgInfo : pkgsWithData) {
1261 if (pkgInfo.applicationInfo != null
1262 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1263 knownUids.put(pkgInfo.applicationInfo.uid, true);
1264 }
1265 }
1266 return knownUids;
1267 }
1268
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001269 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001270 Context context,
1271 int userId) {
1272 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001273 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1274 }
1275
1276 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1277 IAccountAuthenticatorCache authCache,
1278 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001279 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001280 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1281 .getAllServices(userId)) {
1282 knownAuth.put(service.type.type, service.uid);
1283 }
1284 return knownAuth;
1285 }
1286
Amith Yamasani04e0d262012-02-14 11:50:53 -08001287 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001288 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001289 }
1290
1291 protected UserAccounts getUserAccounts(int userId) {
1292 synchronized (mUsers) {
1293 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001294 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001295 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001296 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1297 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001298 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001299 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001300 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001301 validateAccounts = true;
1302 }
1303 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001304 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001305 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001306 synchronized (accounts.dbLock) {
1307 synchronized (accounts.cacheLock) {
1308 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1309 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1310 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001311 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001312 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001313 }
1314 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001315 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001316 }
1317 return accounts;
1318 }
1319 }
1320
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001321 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1322 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001323 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001324 if (!accountsToRemove.isEmpty()) {
Hui Yu139c2482018-08-10 15:37:51 -07001325 Slog.i(TAG, accountsToRemove.size()
1326 + " accounts were previously deleted while user "
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001327 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001328 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1329 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001330
1331 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001332 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001333 }
1334 }
1335 }
1336
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001337 private void purgeOldGrantsAll() {
1338 synchronized (mUsers) {
1339 for (int i = 0; i < mUsers.size(); i++) {
1340 purgeOldGrants(mUsers.valueAt(i));
1341 }
1342 }
1343 }
1344
1345 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001346 synchronized (accounts.dbLock) {
1347 synchronized (accounts.cacheLock) {
1348 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1349 for (int uid : uids) {
1350 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1351 if (packageExists) {
1352 continue;
1353 }
1354 Log.d(TAG, "deleting grants for UID " + uid
1355 + " because its package is no longer installed");
1356 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001357 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001358 }
1359 }
1360 }
1361
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001362 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001363 if (isSpecialPackageKey(packageName)) {
1364 return;
1365 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001366 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001367 int numberOfUsers = mUsers.size();
1368 for (int i = 0; i < numberOfUsers; i++) {
1369 UserAccounts accounts = mUsers.valueAt(i);
1370 try {
1371 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1372 } catch (NameNotFoundException e) {
1373 // package does not exist - remove visibility values
1374 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001375 synchronized (accounts.dbLock) {
1376 synchronized (accounts.cacheLock) {
1377 for (Account account : accounts.visibilityCache.keySet()) {
1378 Map<String, Integer> accountVisibility =
1379 getPackagesAndVisibilityForAccountLocked(account, accounts);
1380 accountVisibility.remove(packageName);
1381 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001382 }
1383 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001384 }
1385 }
1386 }
1387 }
1388
Fyodor Kupolov945c97e2017-06-21 17:45:19 -07001389 private void purgeUserData(int userId) {
Amith Yamasani13593602012-03-22 16:16:17 -07001390 UserAccounts accounts;
1391 synchronized (mUsers) {
1392 accounts = mUsers.get(userId);
1393 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001394 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001395 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001396 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001397 synchronized (accounts.dbLock) {
1398 synchronized (accounts.cacheLock) {
Dmitry Dementyev47443192018-10-24 13:31:59 -07001399 accounts.accountsDb.closeDebugStatement();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001400 accounts.accountsDb.close();
1401 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001402 }
Amith Yamasani13593602012-03-22 16:16:17 -07001403 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001404 }
1405
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001406 @VisibleForTesting
1407 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001408 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1409 }
1410
1411 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001412 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1413 Log.v(TAG, "onUserUnlocked " + userId);
1414 }
1415 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001416 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001417 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001418 if (userId < 1) return;
Fyodor Kupolov2bc895d2017-12-19 11:53:47 -08001419 mHandler.post(() -> syncSharedAccounts(userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001420 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001421
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001422 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001423 // Check if there's a shared account that needs to be created as an account
1424 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1425 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001426 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001427 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001428 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001429 : UserHandle.USER_SYSTEM;
1430 if (parentUserId < 0) {
1431 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1432 return;
1433 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001434 for (Account sa : sharedAccounts) {
1435 if (ArrayUtils.contains(accounts, sa)) continue;
1436 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001437 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001438 }
1439 }
1440
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001441 @Override
1442 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001443 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001444 }
1445
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001446 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001447 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001448 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001449 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1450 Log.v(TAG, "getPassword: " + account
1451 + ", caller's uid " + Binder.getCallingUid()
1452 + ", pid " + Binder.getCallingPid());
1453 }
Fred Quintana382601f2010-03-25 12:25:10 -07001454 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001455 int userId = UserHandle.getCallingUserId();
1456 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001457 String msg = String.format(
1458 "uid %s cannot get secrets for accounts of type: %s",
1459 callingUid,
1460 account.type);
1461 throw new SecurityException(msg);
1462 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001463 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001464 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001465 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001466 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001467 } finally {
1468 restoreCallingIdentity(identityToken);
1469 }
1470 }
1471
Amith Yamasani04e0d262012-02-14 11:50:53 -08001472 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001473 if (account == null) {
1474 return null;
1475 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001476 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001477 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1478 return null;
1479 }
Fred Quintana31957f12009-10-21 13:43:10 -07001480
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001481 synchronized (accounts.dbLock) {
1482 synchronized (accounts.cacheLock) {
1483 return accounts.accountsDb
1484 .findAccountPasswordByNameAndType(account.name, account.type);
1485 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001486 }
1487 }
1488
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001489 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001490 public String getPreviousName(Account account) {
1491 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1492 Log.v(TAG, "getPreviousName: " + account
1493 + ", caller's uid " + Binder.getCallingUid()
1494 + ", pid " + Binder.getCallingPid());
1495 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001496 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001497 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001498 long identityToken = clearCallingIdentity();
1499 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001500 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001501 return readPreviousNameInternal(accounts, account);
1502 } finally {
1503 restoreCallingIdentity(identityToken);
1504 }
1505 }
1506
1507 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1508 if (account == null) {
1509 return null;
1510 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001511 synchronized (accounts.dbLock) {
1512 synchronized (accounts.cacheLock) {
1513 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1514 if (previousNameRef == null) {
1515 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1516 previousNameRef = new AtomicReference<>(previousName);
1517 accounts.previousNameCache.put(account, previousNameRef);
1518 return previousName;
1519 } else {
1520 return previousNameRef.get();
1521 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001522 }
1523 }
1524 }
1525
1526 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001527 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001528 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001529 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001530 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1531 account, key, callingUid, Binder.getCallingPid());
1532 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001533 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001534 Preconditions.checkNotNull(account, "account cannot be null");
1535 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001536 int userId = UserHandle.getCallingUserId();
1537 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001538 String msg = String.format(
1539 "uid %s cannot get user data for accounts of type: %s",
1540 callingUid,
1541 account.type);
1542 throw new SecurityException(msg);
1543 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001544 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001545 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1546 return null;
1547 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001548 long identityToken = clearCallingIdentity();
1549 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001550 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001551 if (!accountExistsCache(accounts, account)) {
1552 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001553 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001554 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001555 } finally {
1556 restoreCallingIdentity(identityToken);
1557 }
1558 }
1559
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001560 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001561 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001562 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001563 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1564 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001565 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001566 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001567 + ", pid " + Binder.getCallingPid());
1568 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001569 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001570 if (isCrossUser(callingUid, userId)) {
1571 throw new SecurityException(
1572 String.format(
1573 "User %s tying to get authenticator types for %s" ,
1574 UserHandle.getCallingUserId(),
1575 userId));
1576 }
1577
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001578 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001579 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001580 return getAuthenticatorTypesInternal(userId);
1581
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001582 } finally {
1583 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001584 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001585 }
1586
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001587 /**
1588 * Should only be called inside of a clearCallingIdentity block.
1589 */
1590 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001591 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001592 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1593 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1594 AuthenticatorDescription[] types =
1595 new AuthenticatorDescription[authenticatorCollection.size()];
1596 int i = 0;
1597 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1598 : authenticatorCollection) {
1599 types[i] = authenticator.type;
1600 i++;
1601 }
1602 return types;
1603 }
1604
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001605 private boolean isCrossUser(int callingUid, int userId) {
1606 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001607 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001608 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001609 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1610 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001611 }
1612
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001613 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001614 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001615 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001616 }
1617
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001618 @Override
1619 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001620 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001621 int callingUid = Binder.getCallingUid();
1622 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1623 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001624 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001625 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001626 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1627 final UserAccounts toAccounts = getUserAccounts(userTo);
1628 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001629 if (response != null) {
1630 Bundle result = new Bundle();
1631 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1632 try {
1633 response.onResult(result);
1634 } catch (RemoteException e) {
1635 Slog.w(TAG, "Failed to report error back to the client." + e);
1636 }
1637 }
1638 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001639 }
1640
Hui Yu139c2482018-08-10 15:37:51 -07001641 Slog.d(TAG, "Copying account " + account.toSafeString()
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001642 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001643 long identityToken = clearCallingIdentity();
1644 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001645 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001646 false /* stripAuthTokenFromResult */, account.name,
1647 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001648 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001649 protected String toDebugString(long now) {
1650 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1651 + ", " + account.type;
1652 }
1653
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001654 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001655 public void run() throws RemoteException {
1656 mAuthenticator.getAccountCredentialsForCloning(this, account);
1657 }
1658
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001659 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001660 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001661 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001662 if (result != null
1663 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1664 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001665 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001666 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001667 super.onResult(result);
1668 }
1669 }
1670 }.bind();
1671 } finally {
1672 restoreCallingIdentity(identityToken);
1673 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001674 }
1675
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001676 @Override
1677 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001678 final int callingUid = Binder.getCallingUid();
1679 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1680 String msg = String.format(
1681 "accountAuthenticated( account: %s, callerUid: %s)",
1682 account,
1683 callingUid);
1684 Log.v(TAG, msg);
1685 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001686 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001687 int userId = UserHandle.getCallingUserId();
1688 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001689 String msg = String.format(
1690 "uid %s cannot notify authentication for accounts of type: %s",
1691 callingUid,
1692 account.type);
1693 throw new SecurityException(msg);
1694 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001695
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001696 if (!canUserModifyAccounts(userId, callingUid) ||
1697 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001698 return false;
1699 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001700
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001701 long identityToken = clearCallingIdentity();
1702 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001703 UserAccounts accounts = getUserAccounts(userId);
1704 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001705 } finally {
1706 restoreCallingIdentity(identityToken);
1707 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001708 }
1709
1710 private boolean updateLastAuthenticatedTime(Account account) {
1711 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001712 synchronized (accounts.dbLock) {
1713 synchronized (accounts.cacheLock) {
1714 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1715 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001716 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001717 }
1718
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001719 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001720 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1721 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001722 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001723 long id = clearCallingIdentity();
1724 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001725 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001726 false /* stripAuthTokenFromResult */, account.name,
1727 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001728 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001729 protected String toDebugString(long now) {
1730 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1731 + ", " + account.type;
1732 }
1733
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001734 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001735 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001736 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001737 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1738 if (acc.equals(account)) {
1739 mAuthenticator.addAccountFromCredentials(
1740 this, account, accountCredentials);
1741 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001742 }
1743 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001744 }
1745
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001746 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001747 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001748 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001749 // TODO: Anything to do if if succedded?
1750 // TODO: If it failed: Show error notification? Should we remove the shadow
1751 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001752 // TODO: what we do with the visibility?
1753
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001754 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001755 }
1756
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001757 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001758 public void onError(int errorCode, String errorMessage) {
1759 super.onError(errorCode, errorMessage);
1760 // TODO: Show error notification to user
1761 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1762 }
1763
1764 }.bind();
1765 } finally {
1766 restoreCallingIdentity(id);
1767 }
1768 }
1769
Amith Yamasani04e0d262012-02-14 11:50:53 -08001770 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001771 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001772 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001773 if (account == null) {
1774 return false;
1775 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001776 if (!isLocalUnlockedUser(accounts.userId)) {
Hui Yu139c2482018-08-10 15:37:51 -07001777 Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
1778 + accounts.userId + " is locked. callingUid=" + callingUid);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001779 return false;
1780 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001781 synchronized (accounts.dbLock) {
1782 synchronized (accounts.cacheLock) {
1783 accounts.accountsDb.beginTransaction();
1784 try {
1785 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001786 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001787 + ", skipping since the account already exists");
1788 return false;
1789 }
1790 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1791 if (accountId < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001792 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001793 + ", skipping the DB insert failed");
1794 return false;
1795 }
1796 // Insert into DE table
1797 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001798 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001799 + ", skipping the DB insert failed");
1800 return false;
1801 }
1802 if (extras != null) {
1803 for (String key : extras.keySet()) {
1804 final String value = extras.getString(key);
1805 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07001806 Log.w(TAG, "insertAccountIntoDatabase: "
1807 + account.toSafeString()
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001808 + ", skipping since insertExtra failed for key " + key);
1809 return false;
1810 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001811 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001812 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001813
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001814 if (packageToVisibility != null) {
1815 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1816 setAccountVisibility(account, entry.getKey() /* package */,
1817 entry.getValue() /* visibility */, false /* notify */,
1818 accounts);
1819 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001820 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001821 accounts.accountsDb.setTransactionSuccessful();
1822
1823 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1824 accountId,
1825 accounts, callingUid);
1826
1827 insertAccountIntoCacheLocked(accounts, account);
1828 } finally {
1829 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001830 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001831 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001832 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001833 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1834 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001835 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001836
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001837 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001838 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1839 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001840
Amith Yamasani5be347b2013-03-31 17:44:31 -07001841 return true;
1842 }
1843
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001844 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001845 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001846 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001847 }
1848 }
1849
Amith Yamasani5be347b2013-03-31 17:44:31 -07001850 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001851 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001852 * running, then clone the account too.
1853 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001854 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001855 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001856 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001857 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001858 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001859 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001860 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001861 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001862 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001863 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001864 }
1865 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001866 }
1867 }
1868
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001869 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001870 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001871 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001872 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001873 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001874 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1875 Log.v(TAG, "hasFeatures: " + account
1876 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001877 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001878 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001879 + ", pid " + Binder.getCallingPid());
1880 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001881 Preconditions.checkArgument(account != null, "account cannot be null");
1882 Preconditions.checkArgument(response != null, "response cannot be null");
1883 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001884 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001885 checkReadAccountsPermitted(callingUid, account.type, userId,
1886 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001887
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001888 long identityToken = clearCallingIdentity();
1889 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001890 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001891 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001892 } finally {
1893 restoreCallingIdentity(identityToken);
1894 }
1895 }
1896
1897 private class TestFeaturesSession extends Session {
1898 private final String[] mFeatures;
1899 private final Account mAccount;
1900
Amith Yamasani04e0d262012-02-14 11:50:53 -08001901 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001902 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001903 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001904 true /* stripAuthTokenFromResult */, account.name,
1905 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001906 mFeatures = features;
1907 mAccount = account;
1908 }
1909
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001910 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001911 public void run() throws RemoteException {
1912 try {
1913 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1914 } catch (RemoteException e) {
1915 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1916 }
1917 }
1918
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001919 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001920 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001921 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001922 IAccountManagerResponse response = getResponseAndClose();
1923 if (response != null) {
1924 try {
1925 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001926 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001927 return;
1928 }
Fred Quintana56285a62010-12-02 14:20:51 -08001929 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1930 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1931 + response);
1932 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001933 final Bundle newResult = new Bundle();
1934 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1935 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1936 response.onResult(newResult);
1937 } catch (RemoteException e) {
1938 // if the caller is dead then there is no one to care about remote exceptions
1939 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1940 Log.v(TAG, "failure while notifying response", e);
1941 }
1942 }
1943 }
1944 }
1945
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001946 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001947 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001948 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001949 + ", " + mAccount
1950 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1951 }
1952 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001953
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001954 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001955 public void renameAccount(
1956 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001957 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001958 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1959 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001960 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001961 + ", pid " + Binder.getCallingPid());
1962 }
1963 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001964 int userId = UserHandle.getCallingUserId();
1965 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001966 String msg = String.format(
1967 "uid %s cannot rename accounts of type: %s",
1968 callingUid,
1969 accountToRename.type);
1970 throw new SecurityException(msg);
1971 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001972 long identityToken = clearCallingIdentity();
1973 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001974 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001975 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001976 Bundle result = new Bundle();
1977 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1978 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001979 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1980 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001981 try {
1982 response.onResult(result);
1983 } catch (RemoteException e) {
1984 Log.w(TAG, e.getMessage());
1985 }
1986 } finally {
1987 restoreCallingIdentity(identityToken);
1988 }
1989 }
1990
1991 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001992 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001993 Account resultAccount = null;
1994 /*
1995 * Cancel existing notifications. Let authenticators
1996 * re-post notifications as required. But we don't know if
1997 * the authenticators have bound their notifications to
1998 * now stale account name data.
1999 *
2000 * With a rename api, we might not need to do this anymore but it
2001 * shouldn't hurt.
2002 */
2003 cancelNotification(
2004 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04002005 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002006 synchronized(accounts.credentialsPermissionNotificationIds) {
2007 for (Pair<Pair<Account, String>, Integer> pair:
2008 accounts.credentialsPermissionNotificationIds.keySet()) {
2009 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002010 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002011 cancelNotification(id, new UserHandle(accounts.userId));
2012 }
2013 }
2014 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002015 synchronized (accounts.dbLock) {
2016 synchronized (accounts.cacheLock) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002017 List<String> accountRemovedReceivers =
2018 getAccountRemovedReceivers(accountToRename, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002019 accounts.accountsDb.beginTransaction();
2020 Account renamedAccount = new Account(newName, accountToRename.type);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002021 try {
chengangf2d081c2017-12-27 17:17:32 +08002022 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
2023 Log.e(TAG, "renameAccount failed - account with new name already exists");
2024 return null;
2025 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002026 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2027 if (accountId >= 0) {
2028 accounts.accountsDb.renameCeAccount(accountId, newName);
2029 if (accounts.accountsDb.renameDeAccount(
2030 accountId, newName, accountToRename.name)) {
2031 accounts.accountsDb.setTransactionSuccessful();
2032 } else {
2033 Log.e(TAG, "renameAccount failed");
2034 return null;
2035 }
2036 } else {
2037 Log.e(TAG, "renameAccount failed - old account does not exist");
2038 return null;
2039 }
2040 } finally {
2041 accounts.accountsDb.endTransaction();
2042 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002043 /*
2044 * Database transaction was successful. Clean up cached
2045 * data associated with the account in the user profile.
2046 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002047 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002048 /*
2049 * Extract the data and token caches before removing the
2050 * old account to preserve the user data associated with
2051 * the account.
2052 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002053 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2054 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2055 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2056 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002057 /*
2058 * Update the cached data associated with the renamed
2059 * account.
2060 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002061 accounts.userDataCache.put(renamedAccount, tmpData);
2062 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2063 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2064 accounts.previousNameCache.put(
2065 renamedAccount,
2066 new AtomicReference<>(accountToRename.name));
2067 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002068
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002069 int parentUserId = accounts.userId;
2070 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002071 /*
2072 * Owner or system user account was renamed, rename the account for
2073 * those users with which the account was shared.
2074 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002075 List<UserInfo> users = getUserManager().getUsers(true);
2076 for (UserInfo user : users) {
2077 if (user.isRestricted()
2078 && (user.restrictedProfileParentId == parentUserId)) {
2079 renameSharedAccountAsUser(accountToRename, newName, user.id);
2080 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002081 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002082 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002083
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002084 sendNotificationAccountUpdated(resultAccount, accounts);
2085 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002086 for (String packageName : accountRemovedReceivers) {
2087 sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2088 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002089 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002090 }
2091 return resultAccount;
2092 }
2093
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002094 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002095 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002096 return userInfo != null && userInfo.canHaveProfile();
2097 }
2098
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002099 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002100 public void removeAccount(IAccountManagerResponse response, Account account,
2101 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002102 removeAccountAsUser(
2103 response,
2104 account,
2105 expectActivityLaunch,
2106 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002107 }
2108
2109 @Override
2110 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002111 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002112 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002113 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2114 Log.v(TAG, "removeAccount: " + account
2115 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002116 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002117 + ", pid " + Binder.getCallingPid()
2118 + ", for user id " + userId);
2119 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002120 Preconditions.checkArgument(account != null, "account cannot be null");
2121 Preconditions.checkArgument(response != null, "response cannot be null");
2122
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002123 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002124 if (isCrossUser(callingUid, userId)) {
2125 throw new SecurityException(
2126 String.format(
2127 "User %s tying remove account for %s" ,
2128 UserHandle.getCallingUserId(),
2129 userId));
2130 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002131 /*
Alex Chauf788f9c2017-12-08 15:16:46 +00002132 * Only the system, authenticator or profile owner should be allowed to remove accounts for
2133 * that authenticator. This will let users remove accounts (via Settings in the system) but
2134 * not arbitrary applications (like competing authenticators).
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002135 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002136 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002137 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
Alex Chauf788f9c2017-12-08 15:16:46 +00002138 && !isSystemUid(callingUid)
2139 && !isProfileOwner(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002140 String msg = String.format(
2141 "uid %s cannot remove accounts of type: %s",
2142 callingUid,
2143 account.type);
2144 throw new SecurityException(msg);
2145 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002146 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002147 try {
2148 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2149 "User cannot modify accounts");
2150 } catch (RemoteException re) {
2151 }
2152 return;
2153 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002154 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002155 try {
2156 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2157 "User cannot modify accounts of this type (policy).");
2158 } catch (RemoteException re) {
2159 }
2160 return;
2161 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002162 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002163 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002164 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002165 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002166 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002167 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002168 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002169 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002170 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002171 }
2172 }
2173 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002174 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002175 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002176 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2177 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002178 accountId,
2179 accounts,
2180 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002181 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002182 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2183 } finally {
2184 restoreCallingIdentity(identityToken);
2185 }
2186 }
2187
2188 @Override
2189 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002190 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002191 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2192 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002193 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002194 + ", pid " + Binder.getCallingPid());
2195 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002196 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002197 if (account == null) {
2198 /*
2199 * Null accounts should result in returning false, as per
2200 * AccountManage.addAccountExplicitly(...) java doc.
2201 */
2202 Log.e(TAG, "account is null");
2203 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002204 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002205 String msg = String.format(
Brandon Weeks9e4e96d2017-08-24 15:24:16 -07002206 "uid %s cannot explicitly remove accounts of type: %s",
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002207 callingUid,
2208 account.type);
2209 throw new SecurityException(msg);
2210 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002211 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002212 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002213 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002214 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2215 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002216 accountId,
2217 accounts,
2218 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002219 long identityToken = clearCallingIdentity();
2220 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002221 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002222 } finally {
2223 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002224 }
Fred Quintana60307342009-03-24 22:48:12 -07002225 }
2226
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002227 private class RemoveAccountSession extends Session {
2228 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002229 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002230 Account account, boolean expectActivityLaunch) {
2231 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002232 true /* stripAuthTokenFromResult */, account.name,
2233 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002234 mAccount = account;
2235 }
2236
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002237 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002238 protected String toDebugString(long now) {
2239 return super.toDebugString(now) + ", removeAccount"
2240 + ", account " + mAccount;
2241 }
2242
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002243 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002244 public void run() throws RemoteException {
2245 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2246 }
2247
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002248 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002249 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002250 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002251 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2252 && !result.containsKey(AccountManager.KEY_INTENT)) {
2253 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002254 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002255 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002256 }
2257 IAccountManagerResponse response = getResponseAndClose();
2258 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002259 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2260 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2261 + response);
2262 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002263 try {
tiansiming5330b5a2017-10-13 10:57:25 +08002264 response.onResult(result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002265 } catch (RemoteException e) {
tiansiming5330b5a2017-10-13 10:57:25 +08002266 Slog.e(TAG, "Error calling onResult()", e);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002267 }
2268 }
2269 }
2270 super.onResult(result);
2271 }
2272 }
2273
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002274 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002275 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002276 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002277 }
2278
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002279 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002280 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002281 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002282 if (!userUnlocked) {
Hui Yu139c2482018-08-10 15:37:51 -07002283 Slog.i(TAG, "Removing account " + account.toSafeString()
2284 + " while user " + accounts.userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002285 + " is still locked. CE data will be removed later");
2286 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002287 synchronized (accounts.dbLock) {
2288 synchronized (accounts.cacheLock) {
2289 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2290 accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002291 List<String> accountRemovedReceivers =
2292 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002293 accounts.accountsDb.beginTransaction();
2294 // Set to a dummy value, this will only be used if the database
2295 // transaction succeeds.
2296 long accountId = -1;
2297 try {
2298 accountId = accounts.accountsDb.findDeAccountId(account);
2299 if (accountId >= 0) {
2300 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002301 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002302 // always delete from CE table if CE storage is available
2303 // DE account could be removed while CE was locked
2304 if (userUnlocked) {
2305 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2306 if (ceAccountId >= 0) {
2307 accounts.accountsDb.deleteCeAccount(ceAccountId);
2308 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002309 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002310 accounts.accountsDb.setTransactionSuccessful();
2311 } finally {
2312 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002313 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002314 if (isChanged) {
2315 removeAccountFromCacheLocked(accounts, account);
2316 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2317 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002318 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2319 || (packageToVisibility.getValue()
2320 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002321 notifyPackage(packageToVisibility.getKey(), accounts);
2322 }
2323 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002324
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002325 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2326 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002327 for (String packageName : accountRemovedReceivers) {
2328 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2329 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002330 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2331 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2332 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2333 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002334 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002335 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002336 long id = Binder.clearCallingIdentity();
2337 try {
2338 int parentUserId = accounts.userId;
2339 if (canHaveProfile(parentUserId)) {
2340 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002341 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002342 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002343 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002344 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002345 }
2346 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002347 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002348 } finally {
2349 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002350 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002351
2352 if (isChanged) {
2353 synchronized (accounts.credentialsPermissionNotificationIds) {
2354 for (Pair<Pair<Account, String>, Integer> key
2355 : accounts.credentialsPermissionNotificationIds.keySet()) {
2356 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002357 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002358 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002359 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002360 account, uid, false));
2361 }
2362 }
2363 }
2364 }
2365
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002366 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002367 }
2368
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002369 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002370 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002371 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002372 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2373 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002374 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2375 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002376 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002377 + ", pid " + Binder.getCallingPid());
2378 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002379 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002380 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002381 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002382 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002383 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002384 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002385 accounts.accountsDb.beginTransaction();
2386 try {
2387 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2388 accounts.accountsDb.setTransactionSuccessful();
2389 } finally {
2390 accounts.accountsDb.endTransaction();
2391 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002392 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002393 for (Pair<Account, String> tokenInfo : deletedTokens) {
2394 Account act = tokenInfo.first;
2395 String tokenType = tokenInfo.second;
2396 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002397 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002398 // wipe out cached token in memory.
2399 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002400 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002401 }
Fred Quintana60307342009-03-24 22:48:12 -07002402 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002403 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002404 }
2405 }
2406
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002407 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002408 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002409 // TODO Move to AccountsDB
2410 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002411 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002412
Fred Quintana33269202009-04-20 16:05:10 -07002413 try {
2414 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002415 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002416 String accountName = cursor.getString(1);
2417 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002418 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002419 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002420 }
Fred Quintana33269202009-04-20 16:05:10 -07002421 } finally {
2422 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002423 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002424 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002425 }
2426
Carlos Valdivia91979be2015-05-22 14:11:35 -07002427 private void saveCachedToken(
2428 UserAccounts accounts,
2429 Account account,
2430 String callerPkg,
2431 byte[] callerSigDigest,
2432 String tokenType,
2433 String token,
2434 long expiryMillis) {
2435
2436 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2437 return;
2438 }
2439 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002440 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002441 synchronized (accounts.cacheLock) {
2442 accounts.accountTokenCaches.put(
2443 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002444 }
2445 }
2446
Amith Yamasani04e0d262012-02-14 11:50:53 -08002447 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2448 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002449 if (account == null || type == null) {
2450 return false;
2451 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002452 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002453 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002454 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002455 accounts.accountsDb.beginTransaction();
2456 boolean updateCache = false;
2457 try {
2458 long accountId = accounts.accountsDb.findDeAccountId(account);
2459 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002460 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002461 }
2462 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2463 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2464 accounts.accountsDb.setTransactionSuccessful();
2465 updateCache = true;
2466 return true;
2467 }
2468 return false;
2469 } finally {
2470 accounts.accountsDb.endTransaction();
2471 if (updateCache) {
2472 synchronized (accounts.cacheLock) {
2473 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2474 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002475 }
Fred Quintana33269202009-04-20 16:05:10 -07002476 }
Fred Quintana60307342009-03-24 22:48:12 -07002477 }
2478 }
2479
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002480 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002481 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002482 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002483 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2484 Log.v(TAG, "peekAuthToken: " + account
2485 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002486 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002487 + ", pid " + Binder.getCallingPid());
2488 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002489 Preconditions.checkNotNull(account, "account cannot be null");
2490 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002491 int userId = UserHandle.getCallingUserId();
2492 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002493 String msg = String.format(
2494 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2495 callingUid,
2496 account.type);
2497 throw new SecurityException(msg);
2498 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002499 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002500 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2501 + callingUid);
2502 return null;
2503 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002504 long identityToken = clearCallingIdentity();
2505 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002506 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002507 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002508 } finally {
2509 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002510 }
Fred Quintana60307342009-03-24 22:48:12 -07002511 }
2512
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002513 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002514 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002515 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002516 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2517 Log.v(TAG, "setAuthToken: " + account
2518 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002519 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002520 + ", pid " + Binder.getCallingPid());
2521 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002522 Preconditions.checkNotNull(account, "account cannot be null");
2523 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002524 int userId = UserHandle.getCallingUserId();
2525 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002526 String msg = String.format(
2527 "uid %s cannot set auth tokens associated with accounts of type: %s",
2528 callingUid,
2529 account.type);
2530 throw new SecurityException(msg);
2531 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002532 long identityToken = clearCallingIdentity();
2533 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002534 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002535 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002536 } finally {
2537 restoreCallingIdentity(identityToken);
2538 }
Fred Quintana60307342009-03-24 22:48:12 -07002539 }
2540
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002541 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002542 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002543 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002544 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2545 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002546 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002547 + ", pid " + Binder.getCallingPid());
2548 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002549 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002550 int userId = UserHandle.getCallingUserId();
2551 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002552 String msg = String.format(
2553 "uid %s cannot set secrets for accounts of type: %s",
2554 callingUid,
2555 account.type);
2556 throw new SecurityException(msg);
2557 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002558 long identityToken = clearCallingIdentity();
2559 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002560 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002561 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002562 } finally {
2563 restoreCallingIdentity(identityToken);
2564 }
Fred Quintana60307342009-03-24 22:48:12 -07002565 }
2566
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002567 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2568 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002569 if (account == null) {
2570 return;
2571 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002572 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002573 synchronized (accounts.dbLock) {
2574 synchronized (accounts.cacheLock) {
2575 accounts.accountsDb.beginTransaction();
2576 try {
2577 final long accountId = accounts.accountsDb.findDeAccountId(account);
2578 if (accountId >= 0) {
2579 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2580 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2581 accounts.authTokenCache.remove(account);
2582 accounts.accountTokenCaches.remove(account);
2583 accounts.accountsDb.setTransactionSuccessful();
2584 // If there is an account whose password will be updated and the database
2585 // transactions succeed, then we say that a change has occured. Even if the
2586 // new password is the same as the old and there were no authtokens to
2587 // delete.
2588 isChanged = true;
2589 String action = (password == null || password.length() == 0) ?
2590 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2591 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2592 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2593 callingUid);
2594 }
2595 } finally {
2596 accounts.accountsDb.endTransaction();
2597 if (isChanged) {
2598 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2599 sendNotificationAccountUpdated(account, accounts);
2600 sendAccountsChangedBroadcast(accounts.userId);
2601 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002602 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002603 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002604 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002605 }
2606
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002607 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002608 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002609 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002610 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2611 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002612 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002613 + ", pid " + Binder.getCallingPid());
2614 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002615 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002616 int userId = UserHandle.getCallingUserId();
2617 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002618 String msg = String.format(
2619 "uid %s cannot clear passwords for accounts of type: %s",
2620 callingUid,
2621 account.type);
2622 throw new SecurityException(msg);
2623 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002624 long identityToken = clearCallingIdentity();
2625 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002626 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002627 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002628 } finally {
2629 restoreCallingIdentity(identityToken);
2630 }
Fred Quintana60307342009-03-24 22:48:12 -07002631 }
2632
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002633 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002634 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002635 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002636 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2637 Log.v(TAG, "setUserData: " + account
2638 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002639 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002640 + ", pid " + Binder.getCallingPid());
2641 }
Fred Quintana382601f2010-03-25 12:25:10 -07002642 if (key == null) throw new IllegalArgumentException("key is null");
2643 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002644 int userId = UserHandle.getCallingUserId();
2645 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002646 String msg = String.format(
2647 "uid %s cannot set user data for accounts of type: %s",
2648 callingUid,
2649 account.type);
2650 throw new SecurityException(msg);
2651 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002652 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002653 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002654 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002655 if (!accountExistsCache(accounts, account)) {
2656 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002657 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002658 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002659 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002660 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002661 }
2662 }
2663
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002664 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2665 synchronized (accounts.cacheLock) {
2666 if (accounts.accountCache.containsKey(account.type)) {
2667 for (Account acc : accounts.accountCache.get(account.type)) {
2668 if (acc.name.equals(account.name)) {
2669 return true;
2670 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002671 }
2672 }
2673 }
2674 return false;
2675 }
2676
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002677 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002678 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002679 synchronized (accounts.dbLock) {
2680 accounts.accountsDb.beginTransaction();
2681 try {
2682 long accountId = accounts.accountsDb.findDeAccountId(account);
2683 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002684 return;
2685 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002686 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2687 if (extrasId < 0) {
2688 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2689 if (extrasId < 0) {
2690 return;
2691 }
2692 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2693 return;
2694 }
2695 accounts.accountsDb.setTransactionSuccessful();
2696 } finally {
2697 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002698 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002699 synchronized (accounts.cacheLock) {
2700 writeUserDataIntoCacheLocked(accounts, account, key, value);
2701 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002702 }
2703 }
2704
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002705 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002706 if (result == null) {
2707 Log.e(TAG, "the result is unexpectedly null", new Exception());
2708 }
2709 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2710 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2711 + response);
2712 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002713 try {
2714 response.onResult(result);
2715 } catch (RemoteException e) {
2716 // if the caller is dead then there is no one to care about remote
2717 // exceptions
2718 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2719 Log.v(TAG, "failure while notifying response", e);
2720 }
2721 }
2722 }
2723
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002724 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002725 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2726 final String authTokenType)
2727 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002728 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2729 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002730
Fred Quintanad9640ec2012-05-23 12:37:00 -07002731 final int callingUid = getCallingUid();
2732 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002733 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002734 throw new SecurityException("can only call from system");
2735 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002736 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002737 long identityToken = clearCallingIdentity();
2738 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002739 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002740 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2741 false /* stripAuthTokenFromResult */, null /* accountName */,
2742 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002743 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002744 protected String toDebugString(long now) {
2745 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002746 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002747 + ", authTokenType " + authTokenType;
2748 }
2749
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002750 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002751 public void run() throws RemoteException {
2752 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2753 }
2754
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002755 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002756 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002757 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002758 if (result != null) {
2759 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2760 Bundle bundle = new Bundle();
2761 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2762 super.onResult(bundle);
2763 return;
2764 } else {
2765 super.onResult(result);
2766 }
2767 }
2768 }.bind();
2769 } finally {
2770 restoreCallingIdentity(identityToken);
2771 }
2772 }
2773
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002774 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002775 public void getAuthToken(
2776 IAccountManagerResponse response,
2777 final Account account,
2778 final String authTokenType,
2779 final boolean notifyOnAuthFailure,
2780 final boolean expectActivityLaunch,
2781 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002782 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002783 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2784 Log.v(TAG, "getAuthToken: " + account
2785 + ", response " + response
2786 + ", authTokenType " + authTokenType
2787 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2788 + ", expectActivityLaunch " + expectActivityLaunch
2789 + ", caller's uid " + Binder.getCallingUid()
2790 + ", pid " + Binder.getCallingPid());
2791 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002792 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002793 try {
2794 if (account == null) {
2795 Slog.w(TAG, "getAuthToken called with null account");
2796 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2797 return;
2798 }
2799 if (authTokenType == null) {
2800 Slog.w(TAG, "getAuthToken called with null authTokenType");
2801 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2802 return;
2803 }
2804 } catch (RemoteException e) {
2805 Slog.w(TAG, "Failed to report error back to the client." + e);
2806 return;
2807 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002808 int userId = UserHandle.getCallingUserId();
2809 long ident = Binder.clearCallingIdentity();
2810 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002811 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002812 try {
2813 accounts = getUserAccounts(userId);
2814 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2815 AuthenticatorDescription.newKey(account.type), accounts.userId);
2816 } finally {
2817 Binder.restoreCallingIdentity(ident);
2818 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002819
Costin Manolachea40c6302010-12-13 14:50:45 -08002820 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002821 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002822
2823 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002824 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002825 final boolean permissionGranted =
2826 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002827
Carlos Valdivia91979be2015-05-22 14:11:35 -07002828 // Get the calling package. We will use it for the purpose of caching.
2829 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002830 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002831 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002832 try {
2833 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2834 } finally {
2835 Binder.restoreCallingIdentity(ident);
2836 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002837 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2838 String msg = String.format(
2839 "Uid %s is attempting to illegally masquerade as package %s!",
2840 callerUid,
2841 callerPkg);
2842 throw new SecurityException(msg);
2843 }
2844
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002845 // let authenticator know the identity of the caller
2846 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2847 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002848
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002849 if (notifyOnAuthFailure) {
2850 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002851 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002852
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002853 long identityToken = clearCallingIdentity();
2854 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002855 // Distill the caller's package signatures into a single digest.
2856 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2857
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002858 // if the caller has permission, do the peek. otherwise go the more expensive
2859 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002860 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002861 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002862 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002863 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002864 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2865 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2866 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002867 onResult(response, result);
2868 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002869 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002870 }
2871
Carlos Valdivia91979be2015-05-22 14:11:35 -07002872 if (customTokens) {
2873 /*
2874 * Look up tokens in the new cache only if the loginOptions don't have parameters
2875 * outside of those expected to be injected by the AccountManager, e.g.
2876 * ANDORID_PACKAGE_NAME.
2877 */
2878 String token = readCachedTokenInternal(
2879 accounts,
2880 account,
2881 authTokenType,
2882 callerPkg,
2883 callerPkgSigDigest);
2884 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002885 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2886 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2887 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002888 Bundle result = new Bundle();
2889 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2890 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2891 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2892 onResult(response, result);
2893 return;
2894 }
2895 }
2896
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002897 new Session(
2898 accounts,
2899 response,
2900 account.type,
2901 expectActivityLaunch,
2902 false /* stripAuthTokenFromResult */,
2903 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002904 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002905 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002906 protected String toDebugString(long now) {
2907 if (loginOptions != null) loginOptions.keySet();
2908 return super.toDebugString(now) + ", getAuthToken"
Hui Yu139c2482018-08-10 15:37:51 -07002909 + ", " + account.toSafeString()
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002910 + ", authTokenType " + authTokenType
2911 + ", loginOptions " + loginOptions
2912 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2913 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002914
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002915 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002916 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002917 // If the caller doesn't have permission then create and return the
2918 // "grant permission" intent instead of the "getAuthToken" intent.
2919 if (!permissionGranted) {
2920 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2921 } else {
2922 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2923 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002924 }
2925
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002926 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002927 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002928 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002929 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002930 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002931 Intent intent = newGrantCredentialsPermissionIntent(
2932 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002933 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002934 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002935 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002936 authTokenType,
2937 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002938 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002939 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002940 onResult(bundle);
2941 return;
2942 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002943 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002944 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002945 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2946 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002947 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002948 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002949 "the type and name should not be empty");
2950 return;
2951 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002952 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002953 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002954 saveAuthTokenToDatabase(
2955 mAccounts,
2956 resultAccount,
2957 authTokenType,
2958 authToken);
2959 }
2960 long expiryMillis = result.getLong(
2961 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2962 if (customTokens
2963 && expiryMillis > System.currentTimeMillis()) {
2964 saveCachedToken(
2965 mAccounts,
2966 account,
2967 callerPkg,
2968 callerPkgSigDigest,
2969 authTokenType,
2970 authToken,
2971 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002972 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002973 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002974
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002975 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002976 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002977 /*
2978 * Make sure that the supplied intent is owned by the authenticator
2979 * giving it to the system. Otherwise a malicious authenticator could
2980 * have users launching arbitrary activities by tricking users to
2981 * interact with malicious notifications.
2982 */
tiansiminga8868bf2017-09-20 13:59:13 +08002983 if (!checkKeyIntent(
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002984 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08002985 intent)) {
2986 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
2987 "invalid intent in bundle returned");
2988 return;
2989 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002990 doNotification(
2991 mAccounts,
2992 account,
2993 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002994 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002995 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002996 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002997 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002998 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002999 }.bind();
3000 } finally {
3001 restoreCallingIdentity(identityToken);
3002 }
Fred Quintana60307342009-03-24 22:48:12 -07003003 }
3004
Carlos Valdivia91979be2015-05-22 14:11:35 -07003005 private byte[] calculatePackageSignatureDigest(String callerPkg) {
3006 MessageDigest digester;
3007 try {
3008 digester = MessageDigest.getInstance("SHA-256");
3009 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
3010 callerPkg, PackageManager.GET_SIGNATURES);
3011 for (Signature sig : pkgInfo.signatures) {
3012 digester.update(sig.toByteArray());
3013 }
3014 } catch (NoSuchAlgorithmException x) {
3015 Log.wtf(TAG, "SHA-256 should be available", x);
3016 digester = null;
3017 } catch (NameNotFoundException e) {
3018 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
3019 digester = null;
3020 }
3021 return (digester == null) ? null : digester.digest();
3022 }
3023
Dianne Hackborn41203752012-08-31 14:05:51 -07003024 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003025 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003026 int uid = intent.getIntExtra(
3027 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3028 String authTokenType = intent.getStringExtra(
3029 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07003030 final String titleAndSubtitle =
3031 mContext.getString(R.string.permission_request_notification_with_subtitle,
3032 account.name);
3033 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07003034 String title = titleAndSubtitle;
3035 String subtitle = "";
3036 if (index > 0) {
3037 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04003038 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07003039 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07003040 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003041 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003042 Notification n =
3043 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3044 .setSmallIcon(android.R.drawable.stat_sys_warning)
3045 .setWhen(0)
3046 .setColor(contextForUser.getColor(
3047 com.android.internal.R.color.system_notification_accent_color))
3048 .setContentTitle(title)
3049 .setContentText(subtitle)
3050 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3051 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
3052 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003053 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003054 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003055 }
3056
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003057 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3058 int uid, AccountAuthenticatorResponse response, String authTokenType,
3059 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003060
3061 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003062
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003063 if (startInNewTask) {
3064 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3065 // Since it was set in Eclair+ we can't change it without breaking apps using
3066 // the intent from a non-Activity context. This is the default behavior.
3067 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3068 }
Chris Wren717a8812017-03-31 15:34:39 -04003069 intent.addCategory(getCredentialPermissionNotificationId(account,
3070 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003071 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003072 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3073 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003074 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003075
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003076 return intent;
3077 }
3078
Chris Wren717a8812017-03-31 15:34:39 -04003079 private NotificationId getCredentialPermissionNotificationId(Account account,
3080 String authTokenType, int uid) {
3081 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003082 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003083 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003084 final Pair<Pair<Account, String>, Integer> key =
3085 new Pair<Pair<Account, String>, Integer>(
3086 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04003087 nId = accounts.credentialsPermissionNotificationIds.get(key);
3088 if (nId == null) {
3089 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3090 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
3091 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3092 nId = new NotificationId(tag, id);
3093 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003094 }
3095 }
Chris Wren717a8812017-03-31 15:34:39 -04003096 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003097 }
3098
Chris Wren717a8812017-03-31 15:34:39 -04003099 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3100 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08003101 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04003102 nId = accounts.signinRequiredNotificationIds.get(account);
3103 if (nId == null) {
3104 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3105 + ":" + account.hashCode();
3106 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3107 nId = new NotificationId(tag, id);
3108 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003109 }
3110 }
Chris Wren717a8812017-03-31 15:34:39 -04003111 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003112 }
3113
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003114 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07003115 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003116 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003117 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003118 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003119 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3120 Log.v(TAG, "addAccount: accountType " + accountType
3121 + ", response " + response
3122 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003123 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003124 + ", expectActivityLaunch " + expectActivityLaunch
3125 + ", caller's uid " + Binder.getCallingUid()
3126 + ", pid " + Binder.getCallingPid());
3127 }
Fred Quintana382601f2010-03-25 12:25:10 -07003128 if (response == null) throw new IllegalArgumentException("response is null");
3129 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003130
Amith Yamasani71e6c692013-03-24 17:39:28 -07003131 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003132 final int uid = Binder.getCallingUid();
3133 final int userId = UserHandle.getUserId(uid);
3134 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003135 try {
3136 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3137 "User is not allowed to add an account!");
3138 } catch (RemoteException re) {
3139 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003140 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003141 return;
3142 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003143 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003144 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003145 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3146 "User cannot modify accounts of this type (policy).");
3147 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003148 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003149 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3150 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003151 return;
3152 }
3153
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003154 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003155 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3156 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3157 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3158
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003159 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003160 long identityToken = clearCallingIdentity();
3161 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003162 UserAccounts accounts = getUserAccounts(usrId);
3163 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003164 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3165 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003166 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003167 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003168 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003169 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003170 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003171 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003172 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003173 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003174
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003175 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003176 protected String toDebugString(long now) {
3177 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003178 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003179 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003180 }
3181 }.bind();
3182 } finally {
3183 restoreCallingIdentity(identityToken);
3184 }
Fred Quintana60307342009-03-24 22:48:12 -07003185 }
3186
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003187 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003188 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3189 final String authTokenType, final String[] requiredFeatures,
3190 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003191 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003192 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003193 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3194 Log.v(TAG, "addAccount: accountType " + accountType
3195 + ", response " + response
3196 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003197 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003198 + ", expectActivityLaunch " + expectActivityLaunch
3199 + ", caller's uid " + Binder.getCallingUid()
3200 + ", pid " + Binder.getCallingPid()
3201 + ", for user id " + userId);
3202 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003203 Preconditions.checkArgument(response != null, "response cannot be null");
3204 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003205 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003206 if (isCrossUser(callingUid, userId)) {
3207 throw new SecurityException(
3208 String.format(
3209 "User %s trying to add account for %s" ,
3210 UserHandle.getCallingUserId(),
3211 userId));
3212 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003213
3214 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003215 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003216 try {
3217 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3218 "User is not allowed to add an account!");
3219 } catch (RemoteException re) {
3220 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003221 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003222 return;
3223 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003224 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003225 try {
3226 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3227 "User cannot modify accounts of this type (policy).");
3228 } catch (RemoteException re) {
3229 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003230 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3231 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003232 return;
3233 }
3234
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003235 final int pid = Binder.getCallingPid();
3236 final int uid = Binder.getCallingUid();
3237 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3238 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3239 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3240
3241 long identityToken = clearCallingIdentity();
3242 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003243 UserAccounts accounts = getUserAccounts(userId);
3244 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003245 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3246 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003247 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003248 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003249 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003250 @Override
3251 public void run() throws RemoteException {
3252 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3253 options);
3254 }
3255
3256 @Override
3257 protected String toDebugString(long now) {
3258 return super.toDebugString(now) + ", addAccount"
3259 + ", accountType " + accountType
3260 + ", requiredFeatures "
3261 + (requiredFeatures != null
3262 ? TextUtils.join(",", requiredFeatures)
3263 : null);
3264 }
3265 }.bind();
3266 } finally {
3267 restoreCallingIdentity(identityToken);
3268 }
3269 }
3270
Sandra Kwan78812282015-11-04 11:19:47 -08003271 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003272 public void startAddAccountSession(
3273 final IAccountManagerResponse response,
3274 final String accountType,
3275 final String authTokenType,
3276 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003277 final boolean expectActivityLaunch,
3278 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003279 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003280 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3281 Log.v(TAG,
3282 "startAddAccountSession: accountType " + accountType
3283 + ", response " + response
3284 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003285 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003286 + ", expectActivityLaunch " + expectActivityLaunch
3287 + ", caller's uid " + Binder.getCallingUid()
3288 + ", pid " + Binder.getCallingPid());
3289 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003290 Preconditions.checkArgument(response != null, "response cannot be null");
3291 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003292
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003293 final int uid = Binder.getCallingUid();
3294 final int userId = UserHandle.getUserId(uid);
3295 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003296 try {
3297 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3298 "User is not allowed to add an account!");
3299 } catch (RemoteException re) {
3300 }
3301 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3302 return;
3303 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003304 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003305 try {
3306 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3307 "User cannot modify accounts of this type (policy).");
3308 } catch (RemoteException re) {
3309 }
3310 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3311 userId);
3312 return;
3313 }
Sandra Kwan78812282015-11-04 11:19:47 -08003314 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003315 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3316 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3317 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3318
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003319 // Check to see if the Password should be included to the caller.
3320 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3321 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003322 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003323
Sandra Kwan78812282015-11-04 11:19:47 -08003324 long identityToken = clearCallingIdentity();
3325 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003326 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003327 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3328 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003329 new StartAccountSession(
3330 accounts,
3331 response,
3332 accountType,
3333 expectActivityLaunch,
3334 null /* accountName */,
3335 false /* authDetailsRequired */,
3336 true /* updateLastAuthenticationTime */,
3337 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003338 @Override
3339 public void run() throws RemoteException {
3340 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3341 requiredFeatures, options);
3342 }
3343
3344 @Override
3345 protected String toDebugString(long now) {
3346 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3347 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3348 + accountType + ", requiredFeatures "
3349 + (requiredFeatures != null ? requiredFeaturesStr : null);
3350 }
3351 }.bind();
3352 } finally {
3353 restoreCallingIdentity(identityToken);
3354 }
3355 }
3356
3357 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3358 private abstract class StartAccountSession extends Session {
3359
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003360 private final boolean mIsPasswordForwardingAllowed;
3361
3362 public StartAccountSession(
3363 UserAccounts accounts,
3364 IAccountManagerResponse response,
3365 String accountType,
3366 boolean expectActivityLaunch,
3367 String accountName,
3368 boolean authDetailsRequired,
3369 boolean updateLastAuthenticationTime,
3370 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003371 super(accounts, response, accountType, expectActivityLaunch,
3372 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3373 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003374 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003375 }
3376
3377 @Override
3378 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003379 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003380 mNumResults++;
3381 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003382 if (result != null
3383 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08003384 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003385 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08003386 intent)) {
3387 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3388 "invalid intent in bundle returned");
3389 return;
3390 }
Sandra Kwan78812282015-11-04 11:19:47 -08003391 }
Sandra Kwan78812282015-11-04 11:19:47 -08003392 IAccountManagerResponse response;
3393 if (mExpectActivityLaunch && result != null
3394 && result.containsKey(AccountManager.KEY_INTENT)) {
3395 response = mResponse;
3396 } else {
3397 response = getResponseAndClose();
3398 }
3399 if (response == null) {
3400 return;
3401 }
3402 if (result == null) {
3403 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3404 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3405 + response);
3406 }
3407 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3408 "null bundle returned");
3409 return;
3410 }
3411
3412 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3413 // All AccountManager error codes are greater
3414 // than 0
3415 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3416 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3417 return;
3418 }
3419
Hongming Jin368aa192016-07-29 14:29:54 -07003420 // Omit passwords if the caller isn't permitted to see them.
3421 if (!mIsPasswordForwardingAllowed) {
3422 result.remove(AccountManager.KEY_PASSWORD);
3423 }
3424
Sandra Kwan78812282015-11-04 11:19:47 -08003425 // Strip auth token from result.
3426 result.remove(AccountManager.KEY_AUTHTOKEN);
3427
3428 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3429 Log.v(TAG,
3430 getClass().getSimpleName() + " calling onResult() on response " + response);
3431 }
3432
3433 // Get the session bundle created by authenticator. The
3434 // bundle contains data necessary for finishing the session
3435 // later. The session bundle will be encrypted here and
3436 // decrypted later when trying to finish the session.
3437 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3438 if (sessionBundle != null) {
3439 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3440 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003441 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003442 Log.w(TAG, "Account type in session bundle doesn't match request.");
3443 }
3444 // Add accountType info to session bundle. This will
3445 // override any value set by authenticator.
3446 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3447
3448 // Encrypt session bundle before returning to caller.
3449 try {
3450 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3451 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3452 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3453 } catch (GeneralSecurityException e) {
3454 if (Log.isLoggable(TAG, Log.DEBUG)) {
3455 Log.v(TAG, "Failed to encrypt session bundle!", e);
3456 }
3457 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3458 "failed to encrypt session bundle");
3459 return;
3460 }
3461 }
3462
3463 sendResponse(response, result);
3464 }
3465 }
3466
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003467 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003468 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003469 @NonNull Bundle sessionBundle,
3470 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003471 Bundle appInfo,
3472 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003473 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003474 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003475 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3476 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003477 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003478 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003479 + ", caller's uid " + callingUid
3480 + ", caller's user id " + UserHandle.getCallingUserId()
3481 + ", pid " + Binder.getCallingPid()
3482 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003483 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003484 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003485 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3486 // Account type is added to it before encryption.
3487 if (sessionBundle == null || sessionBundle.size() == 0) {
3488 throw new IllegalArgumentException("sessionBundle is empty");
3489 }
3490
Dmitry Dementyev52745472016-12-02 10:27:45 -08003491 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003492 if (isCrossUser(callingUid, userId)) {
3493 throw new SecurityException(
3494 String.format(
3495 "User %s trying to finish session for %s without cross user permission",
3496 UserHandle.getCallingUserId(),
3497 userId));
3498 }
3499
Sandra Kwan0b84b452016-01-20 15:25:42 -08003500 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003501 sendErrorResponse(response,
3502 AccountManager.ERROR_CODE_USER_RESTRICTED,
3503 "User is not allowed to add an account!");
3504 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3505 return;
3506 }
3507
3508 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003509 final Bundle decryptedBundle;
3510 final String accountType;
3511 // First decrypt session bundle to get account type for checking permission.
3512 try {
3513 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3514 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3515 if (decryptedBundle == null) {
3516 sendErrorResponse(
3517 response,
3518 AccountManager.ERROR_CODE_BAD_REQUEST,
3519 "failed to decrypt session bundle");
3520 return;
3521 }
3522 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3523 // Account type cannot be null. This should not happen if session bundle was created
3524 // properly by #StartAccountSession.
3525 if (TextUtils.isEmpty(accountType)) {
3526 sendErrorResponse(
3527 response,
3528 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3529 "accountType is empty");
3530 return;
3531 }
3532
3533 // If by any chances, decryptedBundle contains colliding keys with
3534 // system info
3535 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3536 // update credentials flow, we should replace with the new values of the current call.
3537 if (appInfo != null) {
3538 decryptedBundle.putAll(appInfo);
3539 }
3540
3541 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003542 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003543 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3544 } catch (GeneralSecurityException e) {
3545 if (Log.isLoggable(TAG, Log.DEBUG)) {
3546 Log.v(TAG, "Failed to decrypt session bundle!", e);
3547 }
3548 sendErrorResponse(
3549 response,
3550 AccountManager.ERROR_CODE_BAD_REQUEST,
3551 "failed to decrypt session bundle");
3552 return;
3553 }
3554
Sandra Kwan0b84b452016-01-20 15:25:42 -08003555 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003556 sendErrorResponse(
3557 response,
3558 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3559 "User cannot modify accounts of this type (policy).");
3560 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3561 userId);
3562 return;
3563 }
3564
3565 long identityToken = clearCallingIdentity();
3566 try {
3567 UserAccounts accounts = getUserAccounts(userId);
3568 logRecordWithUid(
3569 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003570 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3571 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003572 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003573 new Session(
3574 accounts,
3575 response,
3576 accountType,
3577 expectActivityLaunch,
3578 true /* stripAuthTokenFromResult */,
3579 null /* accountName */,
3580 false /* authDetailsRequired */,
3581 true /* updateLastAuthenticationTime */) {
3582 @Override
3583 public void run() throws RemoteException {
3584 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3585 }
3586
3587 @Override
3588 protected String toDebugString(long now) {
3589 return super.toDebugString(now)
3590 + ", finishSession"
3591 + ", accountType " + accountType;
3592 }
3593 }.bind();
3594 } finally {
3595 restoreCallingIdentity(identityToken);
3596 }
3597 }
3598
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003599 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003600 final DevicePolicyManagerInternal dpmi =
3601 LocalServices.getService(DevicePolicyManagerInternal.class);
3602 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003603 if (dpmi == null) {
3604 intent = getDefaultCantAddAccountIntent(errorCode);
3605 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003606 intent = dpmi.createUserRestrictionSupportIntent(userId,
3607 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3608 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3609 intent = dpmi.createShowAdminSupportIntent(userId, false);
3610 }
3611 if (intent == null) {
3612 intent = getDefaultCantAddAccountIntent(errorCode);
3613 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003614 long identityToken = clearCallingIdentity();
3615 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003616 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003617 } finally {
3618 restoreCallingIdentity(identityToken);
3619 }
3620 }
3621
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003622 /**
3623 * Called when we don't know precisely who is preventing us from adding an account.
3624 */
3625 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3626 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3627 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3628 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3629 return cantAddAccount;
3630 }
3631
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003632 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003633 public void confirmCredentialsAsUser(
3634 IAccountManagerResponse response,
3635 final Account account,
3636 final Bundle options,
3637 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003638 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003639 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003640 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003641 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3642 Log.v(TAG, "confirmCredentials: " + account
3643 + ", response " + response
3644 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003645 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003646 + ", pid " + Binder.getCallingPid());
3647 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003648 // Only allow the system process to read accounts of other users
3649 if (isCrossUser(callingUid, userId)) {
3650 throw new SecurityException(
3651 String.format(
3652 "User %s trying to confirm account credentials for %s" ,
3653 UserHandle.getCallingUserId(),
3654 userId));
3655 }
Fred Quintana382601f2010-03-25 12:25:10 -07003656 if (response == null) throw new IllegalArgumentException("response is null");
3657 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003658 long identityToken = clearCallingIdentity();
3659 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003660 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003661 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003662 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003663 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003664 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003665 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003666 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003667 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003668 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003669 protected String toDebugString(long now) {
3670 return super.toDebugString(now) + ", confirmCredentials"
Hui Yu139c2482018-08-10 15:37:51 -07003671 + ", " + account.toSafeString();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003672 }
3673 }.bind();
3674 } finally {
3675 restoreCallingIdentity(identityToken);
3676 }
Fred Quintana60307342009-03-24 22:48:12 -07003677 }
3678
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003679 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003680 public void updateCredentials(IAccountManagerResponse response, final Account account,
3681 final String authTokenType, final boolean expectActivityLaunch,
3682 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003683 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003684 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3685 Log.v(TAG, "updateCredentials: " + account
3686 + ", response " + response
3687 + ", authTokenType " + authTokenType
3688 + ", expectActivityLaunch " + expectActivityLaunch
3689 + ", caller's uid " + Binder.getCallingUid()
3690 + ", pid " + Binder.getCallingPid());
3691 }
Fred Quintana382601f2010-03-25 12:25:10 -07003692 if (response == null) throw new IllegalArgumentException("response is null");
3693 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003694 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003695 long identityToken = clearCallingIdentity();
3696 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003697 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003698 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003699 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003700 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003701 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003702 public void run() throws RemoteException {
3703 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3704 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003705 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003706 protected String toDebugString(long now) {
3707 if (loginOptions != null) loginOptions.keySet();
3708 return super.toDebugString(now) + ", updateCredentials"
Hui Yu139c2482018-08-10 15:37:51 -07003709 + ", " + account.toSafeString()
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003710 + ", authTokenType " + authTokenType
3711 + ", loginOptions " + loginOptions;
3712 }
3713 }.bind();
3714 } finally {
3715 restoreCallingIdentity(identityToken);
3716 }
Fred Quintana60307342009-03-24 22:48:12 -07003717 }
3718
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003719 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003720 public void startUpdateCredentialsSession(
3721 IAccountManagerResponse response,
3722 final Account account,
3723 final String authTokenType,
3724 final boolean expectActivityLaunch,
3725 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003726 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003727 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3728 Log.v(TAG,
3729 "startUpdateCredentialsSession: " + account + ", response " + response
3730 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3731 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3732 + ", pid " + Binder.getCallingPid());
3733 }
3734 if (response == null) {
3735 throw new IllegalArgumentException("response is null");
3736 }
3737 if (account == null) {
3738 throw new IllegalArgumentException("account is null");
3739 }
Sandra Kwana578d112015-12-16 16:01:43 -08003740
3741 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003742 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003743
3744 // Check to see if the Password should be included to the caller.
3745 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3746 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003747 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003748
Sandra Kwane68c37e2015-11-12 17:11:49 -08003749 long identityToken = clearCallingIdentity();
3750 try {
3751 UserAccounts accounts = getUserAccounts(userId);
3752 new StartAccountSession(
3753 accounts,
3754 response,
3755 account.type,
3756 expectActivityLaunch,
3757 account.name,
3758 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003759 true /* updateLastCredentialTime */,
3760 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003761 @Override
3762 public void run() throws RemoteException {
3763 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3764 loginOptions);
3765 }
3766
3767 @Override
3768 protected String toDebugString(long now) {
3769 if (loginOptions != null)
3770 loginOptions.keySet();
3771 return super.toDebugString(now)
3772 + ", startUpdateCredentialsSession"
Hui Yu139c2482018-08-10 15:37:51 -07003773 + ", " + account.toSafeString()
Sandra Kwane68c37e2015-11-12 17:11:49 -08003774 + ", authTokenType " + authTokenType
3775 + ", loginOptions " + loginOptions;
3776 }
3777 }.bind();
3778 } finally {
3779 restoreCallingIdentity(identityToken);
3780 }
3781 }
3782
3783 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003784 public void isCredentialsUpdateSuggested(
3785 IAccountManagerResponse response,
3786 final Account account,
3787 final String statusToken) {
3788 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3789 Log.v(TAG,
3790 "isCredentialsUpdateSuggested: " + account + ", response " + response
3791 + ", caller's uid " + Binder.getCallingUid()
3792 + ", pid " + Binder.getCallingPid());
3793 }
3794 if (response == null) {
3795 throw new IllegalArgumentException("response is null");
3796 }
3797 if (account == null) {
3798 throw new IllegalArgumentException("account is null");
3799 }
3800 if (TextUtils.isEmpty(statusToken)) {
3801 throw new IllegalArgumentException("status token is empty");
3802 }
3803
Sandra Kwan390c9d22016-01-12 14:13:37 -08003804 int usrId = UserHandle.getCallingUserId();
3805 long identityToken = clearCallingIdentity();
3806 try {
3807 UserAccounts accounts = getUserAccounts(usrId);
3808 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3809 false /* stripAuthTokenFromResult */, account.name,
3810 false /* authDetailsRequired */) {
3811 @Override
3812 protected String toDebugString(long now) {
3813 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
Hui Yu139c2482018-08-10 15:37:51 -07003814 + ", " + account.toSafeString();
Sandra Kwan390c9d22016-01-12 14:13:37 -08003815 }
3816
3817 @Override
3818 public void run() throws RemoteException {
3819 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3820 }
3821
3822 @Override
3823 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003824 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003825 IAccountManagerResponse response = getResponseAndClose();
3826 if (response == null) {
3827 return;
3828 }
3829
3830 if (result == null) {
3831 sendErrorResponse(
3832 response,
3833 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3834 "null bundle");
3835 return;
3836 }
3837
3838 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3839 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3840 + response);
3841 }
3842 // Check to see if an error occurred. We know if an error occurred because all
3843 // error codes are greater than 0.
3844 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3845 sendErrorResponse(response,
3846 result.getInt(AccountManager.KEY_ERROR_CODE),
3847 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3848 return;
3849 }
3850 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3851 sendErrorResponse(
3852 response,
3853 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3854 "no result in response");
3855 return;
3856 }
3857 final Bundle newResult = new Bundle();
3858 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3859 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3860 sendResponse(response, newResult);
3861 }
3862 }.bind();
3863 } finally {
3864 restoreCallingIdentity(identityToken);
3865 }
3866 }
3867
3868 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003869 public void editProperties(IAccountManagerResponse response, final String accountType,
3870 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003871 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003872 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3873 Log.v(TAG, "editProperties: accountType " + accountType
3874 + ", response " + response
3875 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003876 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003877 + ", pid " + Binder.getCallingPid());
3878 }
Fred Quintana382601f2010-03-25 12:25:10 -07003879 if (response == null) throw new IllegalArgumentException("response is null");
3880 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003881 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003882 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3883 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003884 String msg = String.format(
3885 "uid %s cannot edit authenticator properites for account type: %s",
3886 callingUid,
3887 accountType);
3888 throw new SecurityException(msg);
3889 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003890 long identityToken = clearCallingIdentity();
3891 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003892 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003893 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003894 true /* stripAuthTokenFromResult */, null /* accountName */,
3895 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003896 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003897 public void run() throws RemoteException {
3898 mAuthenticator.editProperties(this, mAccountType);
3899 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003900 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003901 protected String toDebugString(long now) {
3902 return super.toDebugString(now) + ", editProperties"
3903 + ", accountType " + accountType;
3904 }
3905 }.bind();
3906 } finally {
3907 restoreCallingIdentity(identityToken);
3908 }
Fred Quintana60307342009-03-24 22:48:12 -07003909 }
3910
Amith Yamasani12747872015-12-07 14:19:49 -08003911 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003912 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3913 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003914 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003915 throw new SecurityException("Can be called only by system UID");
3916 }
3917 Preconditions.checkNotNull(account, "account cannot be null");
3918 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3919 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3920
3921 final int userId = userHandle.getIdentifier();
3922
3923 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3924
3925 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003926 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003927 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003928 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003929 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003930 return false;
3931 }
3932 }
3933
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003934 // Returns package with oldest target SDK for given UID.
3935 private String getPackageNameForUid(int uid) {
3936 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3937 if (ArrayUtils.isEmpty(packageNames)) {
3938 return null;
3939 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003940 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003941 if (packageNames.length == 1) {
3942 return packageName;
3943 }
3944 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003945 int oldestVersion = Integer.MAX_VALUE;
3946 for (String name : packageNames) {
3947 try {
3948 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3949 if (applicationInfo != null) {
3950 int version = applicationInfo.targetSdkVersion;
3951 if (version < oldestVersion) {
3952 oldestVersion = version;
3953 packageName = name;
3954 }
3955 }
3956 } catch (NameNotFoundException e) {
3957 // skip
3958 }
3959 }
3960 return packageName;
3961 }
3962
Svet Ganovf6d424f12016-09-20 20:18:53 -07003963 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3964 int uid) {
3965 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003966 packageName = getPackageNameForUid(uid);
3967 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003968 return false;
3969 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003970 }
3971
3972 // Use null token which means any token. Having a token means the package
3973 // is trusted by the authenticator, hence it is fine to access the account.
3974 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3975 return true;
3976 }
3977 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003978 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003979
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003980 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003981 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003982 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003983 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003984 }
3985
3986 @Override
3987 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3988 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003989 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003990 throw new SecurityException("Can be called only by system UID");
3991 }
3992
3993 Preconditions.checkNotNull(account, "account cannot be null");
3994 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3995 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3996
3997 final int userId = userHandle.getIdentifier();
3998
3999 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
4000
4001 final int uid;
4002 try {
4003 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
4004 } catch (NameNotFoundException e) {
4005 Slog.e(TAG, "Unknown package " + packageName);
4006 return null;
4007 }
4008
4009 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
4010
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07004011 final long identity = Binder.clearCallingIdentity();
4012 try {
4013 return PendingIntent.getActivityAsUser(
4014 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
4015 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
4016 null, new UserHandle(userId)).getIntentSender();
4017 } finally {
4018 Binder.restoreCallingIdentity(identity);
4019 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004020 }
4021
4022 private Intent newRequestAccountAccessIntent(Account account, String packageName,
4023 int uid, RemoteCallback callback) {
4024 return newGrantCredentialsPermissionIntent(account, packageName, uid,
4025 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
4026 @Override
4027 public void onResult(Bundle value) throws RemoteException {
4028 handleAuthenticatorResponse(true);
4029 }
4030
4031 @Override
4032 public void onRequestContinued() {
4033 /* ignore */
4034 }
4035
4036 @Override
4037 public void onError(int errorCode, String errorMessage) throws RemoteException {
4038 handleAuthenticatorResponse(false);
4039 }
4040
4041 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4042 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07004043 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004044 UserHandle.getUserHandleForUid(uid));
4045 if (callback != null) {
4046 Bundle result = new Bundle();
4047 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4048 callback.sendResult(result);
4049 }
4050 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07004051 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004052 }
4053
4054 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08004055 public boolean someUserHasAccount(@NonNull final Account account) {
4056 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4057 throw new SecurityException("Only system can check for accounts across users");
4058 }
4059 final long token = Binder.clearCallingIdentity();
4060 try {
4061 AccountAndUser[] allAccounts = getAllAccounts();
4062 for (int i = allAccounts.length - 1; i >= 0; i--) {
4063 if (allAccounts[i].account.equals(account)) {
4064 return true;
4065 }
4066 }
4067 return false;
4068 } finally {
4069 Binder.restoreCallingIdentity(token);
4070 }
4071 }
4072
Fred Quintana33269202009-04-20 16:05:10 -07004073 private class GetAccountsByTypeAndFeatureSession extends Session {
4074 private final String[] mFeatures;
4075 private volatile Account[] mAccountsOfType = null;
4076 private volatile ArrayList<Account> mAccountsWithFeatures = null;
4077 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004078 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004079 private final String mPackageName;
sunjianf29d5492017-05-11 15:42:31 -07004080 private final boolean mIncludeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004081
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004082 public GetAccountsByTypeAndFeatureSession(
4083 UserAccounts accounts,
4084 IAccountManagerResponse response,
4085 String type,
4086 String[] features,
4087 int callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004088 String packageName,
4089 boolean includeManagedNotVisible) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004090 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004091 true /* stripAuthTokenFromResult */, null /* accountName */,
4092 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004093 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07004094 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004095 mPackageName = packageName;
sunjianf29d5492017-05-11 15:42:31 -07004096 mIncludeManagedNotVisible = includeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004097 }
4098
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004099 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004100 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004101 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
sunjianf29d5492017-05-11 15:42:31 -07004102 mCallingUid, mPackageName, mIncludeManagedNotVisible);
Fred Quintana33269202009-04-20 16:05:10 -07004103 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07004104 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07004105 mCurrentAccount = 0;
4106
4107 checkAccount();
4108 }
4109
4110 public void checkAccount() {
4111 if (mCurrentAccount >= mAccountsOfType.length) {
4112 sendResult();
4113 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07004114 }
Fred Quintana33269202009-04-20 16:05:10 -07004115
Fred Quintana29e94b82010-03-10 12:11:51 -08004116 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4117 if (accountAuthenticator == null) {
4118 // It is possible that the authenticator has died, which is indicated by
4119 // mAuthenticator being set to null. If this happens then just abort.
4120 // There is no need to send back a result or error in this case since
4121 // that already happened when mAuthenticator was cleared.
4122 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4123 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4124 + " connected to the authenticator, " + toDebugString());
4125 }
4126 return;
4127 }
Fred Quintana33269202009-04-20 16:05:10 -07004128 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004129 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004130 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004131 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004132 }
4133 }
4134
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004135 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004136 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004137 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004138 mNumResults++;
4139 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004140 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004141 return;
4142 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004143 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004144 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4145 }
4146 mCurrentAccount++;
4147 checkAccount();
4148 }
4149
4150 public void sendResult() {
4151 IAccountManagerResponse response = getResponseAndClose();
4152 if (response != null) {
4153 try {
4154 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4155 for (int i = 0; i < accounts.length; i++) {
4156 accounts[i] = mAccountsWithFeatures.get(i);
4157 }
Fred Quintana56285a62010-12-02 14:20:51 -08004158 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4159 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4160 + response);
4161 }
Fred Quintana33269202009-04-20 16:05:10 -07004162 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004163 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004164 response.onResult(result);
4165 } catch (RemoteException e) {
4166 // if the caller is dead then there is no one to care about remote exceptions
4167 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4168 Log.v(TAG, "failure while notifying response", e);
4169 }
4170 }
4171 }
4172 }
4173
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004174 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004175 protected String toDebugString(long now) {
4176 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4177 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4178 }
4179 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004180
Amith Yamasani04e0d262012-02-14 11:50:53 -08004181 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004182 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004183 * @hide
4184 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004185 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004186 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004187 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004188 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004189 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4190 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004191 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004192 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004193 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004194 long identityToken = clearCallingIdentity();
4195 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004196 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004197 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004198 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004199 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004200 opPackageName,
4201 visibleAccountTypes,
4202 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004203 } finally {
4204 restoreCallingIdentity(identityToken);
4205 }
4206 }
4207
Amith Yamasanif29f2362012-04-05 18:29:52 -07004208 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004209 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004210 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004211 * @hide
4212 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004213 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004214 public AccountAndUser[] getRunningAccounts() {
4215 final int[] runningUserIds;
4216 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004217 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004218 } catch (RemoteException e) {
4219 // Running in system_server; should never happen
4220 throw new RuntimeException(e);
4221 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004222 return getAccounts(runningUserIds);
4223 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004224
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004225 /**
4226 * Returns accounts for all users, ignores visibility values.
4227 *
4228 * @hide
4229 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004230 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004231 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004232 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004233 final int[] userIds = new int[users.size()];
4234 for (int i = 0; i < userIds.length; i++) {
4235 userIds[i] = users.get(i).id;
4236 }
4237 return getAccounts(userIds);
4238 }
4239
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004240 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004241 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004242 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004243 for (int userId : userIds) {
4244 UserAccounts userAccounts = getUserAccounts(userId);
4245 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004246 Account[] accounts = getAccountsFromCache(
4247 userAccounts,
4248 null /* type */,
4249 Binder.getCallingUid(),
4250 null /* packageName */,
4251 false /* include managed not visible*/);
4252 for (Account account : accounts) {
4253 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004254 }
4255 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004256
4257 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4258 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004259 }
4260
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004261 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004262 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004263 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004264 int callingUid = Binder.getCallingUid();
4265 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004266 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004267 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004268 }
4269
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004270 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004271 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004272 String type,
4273 int userId,
4274 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004275 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004276 String opPackageName,
4277 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004278 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004279 // Only allow the system process to read accounts of other users
4280 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004281 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004282 && mContext.checkCallingOrSelfPermission(
4283 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4284 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004285 throw new SecurityException("User " + UserHandle.getCallingUserId()
4286 + " trying to get account for " + userId);
4287 }
4288
Fred Quintana56285a62010-12-02 14:20:51 -08004289 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4290 Log.v(TAG, "getAccounts: accountType " + type
4291 + ", caller's uid " + Binder.getCallingUid()
4292 + ", pid " + Binder.getCallingPid());
4293 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004294
4295 // If the original calling app was using account choosing activity
4296 // provided by the framework or authenticator we'll passing in
4297 // the original caller's uid here, which is what should be used for filtering.
4298 List<String> managedTypes =
4299 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4300 if (packageUid != -1 &&
4301 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4302 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004303 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004304 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004305 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004306 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4307 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004308 if (visibleAccountTypes.isEmpty()
4309 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004310 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004311 } else if (visibleAccountTypes.contains(type)) {
4312 // Prune the list down to just the requested type.
4313 visibleAccountTypes = new ArrayList<>();
4314 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004315 } // else aggregate all the visible accounts (it won't matter if the
4316 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004317
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004318 long identityToken = clearCallingIdentity();
4319 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004320 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004321 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004322 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004323 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004324 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004325 visibleAccountTypes,
4326 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004327 } finally {
4328 restoreCallingIdentity(identityToken);
4329 }
4330 }
4331
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004332 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004333 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004334 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004335 int callingUid,
4336 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004337 List<String> visibleAccountTypes,
4338 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004339 ArrayList<Account> visibleAccounts = new ArrayList<>();
4340 for (String visibleType : visibleAccountTypes) {
4341 Account[] accountsForType = getAccountsFromCache(
4342 userAccounts, visibleType, callingUid, callingPackage,
4343 includeUserManagedNotVisible);
4344 if (accountsForType != null) {
4345 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004346 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004347 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004348 Account[] result = new Account[visibleAccounts.size()];
4349 for (int i = 0; i < visibleAccounts.size(); i++) {
4350 result[i] = visibleAccounts.get(i);
4351 }
4352 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004353 }
4354
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004355 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004356 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4357 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004358 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004359 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004360 for (Account account : accounts) {
4361 addSharedAccountAsUser(account, userId);
4362 }
4363 }
4364
4365 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004366 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004367 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004368 accounts.accountsDb.deleteSharedAccount(account);
4369 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004370 if (accountId < 0) {
Hui Yu139c2482018-08-10 15:37:51 -07004371 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
Amith Yamasani67df64b2012-12-14 12:09:36 -08004372 + ", skipping the DB insert failed");
4373 return false;
4374 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004375 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4376 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004377 return true;
4378 }
4379
4380 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004381 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4382 userId = handleIncomingUser(userId);
4383 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004384 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4385 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004386 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004387 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004388 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004389 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004390 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004391 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004392 }
4393 return r > 0;
4394 }
4395
4396 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004397 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004398 return removeSharedAccountAsUser(account, userId, getCallingUid());
4399 }
4400
4401 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004402 userId = handleIncomingUser(userId);
4403 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004404 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4405 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004406 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004407 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004408 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004409 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004410 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004411 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004412 }
4413
4414 @Override
4415 public Account[] getSharedAccountsAsUser(int userId) {
4416 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004417 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004418 synchronized (accounts.dbLock) {
4419 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4420 Account[] accountArray = new Account[accountList.size()];
4421 accountList.toArray(accountArray);
4422 return accountArray;
4423 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004424 }
4425
4426 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004427 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004428 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004429 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004430 }
4431
Amith Yamasani27db4682013-03-30 17:07:47 -07004432 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004433 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004434 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004435 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004436 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004437 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004438 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4439 + callingUid + " with uid=" + uid);
4440 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004441 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004442 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004443 }
4444
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004445 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004446 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004447 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4448 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004449 int callingUid = Binder.getCallingUid();
4450 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004451 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004452 int packageUid = -1;
4453 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004454 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4455 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004456 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004457 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004458 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004459 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004460 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4461 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004462 }
sunjiand62dc392017-06-01 12:05:59 -07004463 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4464 return getAccountsAsUserForPackage(type, userId,
4465 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4466 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004467 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004468 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004469 }
4470
sunjianf29d5492017-05-11 15:42:31 -07004471 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4472 if (accounts.length < 1) return false;
4473 if (accounts.length > 1) return true;
4474 Account account = accounts[0];
4475 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4476 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4477 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4478 return false;
4479 }
4480
4481 private void startChooseAccountActivityWithAccounts(
sunjianbdabd402017-06-06 17:54:07 -07004482 IAccountManagerResponse response, Account[] accounts, String callingPackage) {
sunjianf29d5492017-05-11 15:42:31 -07004483 Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4484 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4485 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4486 new AccountManagerResponse(response));
sunjianbdabd402017-06-06 17:54:07 -07004487 intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004488
4489 mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4490 }
4491
4492 private void handleGetAccountsResult(
4493 IAccountManagerResponse response,
4494 Account[] accounts,
4495 String callingPackage) {
4496
4497 if (needToStartChooseAccountActivity(accounts, callingPackage)) {
sunjianbdabd402017-06-06 17:54:07 -07004498 startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004499 return;
4500 }
4501 if (accounts.length == 1) {
4502 Bundle bundle = new Bundle();
4503 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4504 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4505 onResult(response, bundle);
4506 return;
4507 }
4508 // No qualified account exists, return an empty Bundle.
4509 onResult(response, new Bundle());
4510 }
4511
4512 @Override
4513 public void getAccountByTypeAndFeatures(
4514 IAccountManagerResponse response,
4515 String accountType,
4516 String[] features,
4517 String opPackageName) {
4518
4519 int callingUid = Binder.getCallingUid();
4520 mAppOpsManager.checkPackage(callingUid, opPackageName);
4521 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4522 Log.v(TAG, "getAccount: accountType " + accountType
4523 + ", response " + response
4524 + ", features " + Arrays.toString(features)
4525 + ", caller's uid " + callingUid
4526 + ", pid " + Binder.getCallingPid());
4527 }
4528 if (response == null) throw new IllegalArgumentException("response is null");
4529 if (accountType == null) throw new IllegalArgumentException("accountType is null");
4530
4531 int userId = UserHandle.getCallingUserId();
4532
4533 long identityToken = clearCallingIdentity();
4534 try {
4535 UserAccounts userAccounts = getUserAccounts(userId);
4536 if (ArrayUtils.isEmpty(features)) {
4537 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4538 userAccounts, accountType, callingUid, opPackageName,
4539 true /* include managed not visible */);
4540 handleGetAccountsResult(
4541 response, accountsWithManagedNotVisible, opPackageName);
4542 return;
4543 }
4544
4545 IAccountManagerResponse retrieveAccountsResponse =
4546 new IAccountManagerResponse.Stub() {
4547 @Override
4548 public void onResult(Bundle value) throws RemoteException {
4549 Parcelable[] parcelables = value.getParcelableArray(
4550 AccountManager.KEY_ACCOUNTS);
4551 Account[] accounts = new Account[parcelables.length];
4552 for (int i = 0; i < parcelables.length; i++) {
4553 accounts[i] = (Account) parcelables[i];
4554 }
4555 handleGetAccountsResult(
4556 response, accounts, opPackageName);
4557 }
4558
4559 @Override
4560 public void onError(int errorCode, String errorMessage)
4561 throws RemoteException {
4562 // Will not be called in this case.
4563 }
4564 };
4565 new GetAccountsByTypeAndFeatureSession(
4566 userAccounts,
4567 retrieveAccountsResponse,
4568 accountType,
4569 features,
4570 callingUid,
4571 opPackageName,
4572 true /* include managed not visible */).bind();
4573 } finally {
4574 restoreCallingIdentity(identityToken);
4575 }
4576 }
4577
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004578 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004579 public void getAccountsByFeatures(
4580 IAccountManagerResponse response,
4581 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004582 String[] features,
4583 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004584 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004585 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004586 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4587 Log.v(TAG, "getAccounts: accountType " + type
4588 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004589 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004590 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004591 + ", pid " + Binder.getCallingPid());
4592 }
Fred Quintana382601f2010-03-25 12:25:10 -07004593 if (response == null) throw new IllegalArgumentException("response is null");
4594 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004595 int userId = UserHandle.getCallingUserId();
4596
Svetoslavf3f02ac2015-09-08 14:36:35 -07004597 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4598 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004599 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004600 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004601 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004602 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004603 try {
4604 response.onResult(result);
4605 } catch (RemoteException e) {
4606 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4607 }
4608 return;
4609 }
sunjianf29d5492017-05-11 15:42:31 -07004610
Fred Quintana33269202009-04-20 16:05:10 -07004611 long identityToken = clearCallingIdentity();
4612 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004613 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004614 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004615 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4616 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004617 Bundle result = new Bundle();
4618 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4619 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004620 return;
4621 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004622 new GetAccountsByTypeAndFeatureSession(
4623 userAccounts,
4624 response,
4625 type,
4626 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004627 callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004628 opPackageName,
4629 false /* include managed not visible */).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004630 } finally {
4631 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004632 }
4633 }
4634
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004635 @Override
4636 public void onAccountAccessed(String token) throws RemoteException {
4637 final int uid = Binder.getCallingUid();
4638 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4639 return;
4640 }
4641 final int userId = UserHandle.getCallingUserId();
4642 final long identity = Binder.clearCallingIdentity();
4643 try {
4644 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4645 if (Objects.equals(account.getAccessId(), token)) {
4646 // An app just accessed the account. At this point it knows about
4647 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004648 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004649 if (!hasAccountAccess(account, null, uid)) {
4650 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4651 uid, true);
4652 }
4653 }
4654 }
4655 } finally {
4656 Binder.restoreCallingIdentity(identity);
4657 }
4658 }
4659
Hongming Jin8e2bfc12018-05-30 11:01:06 -07004660 @Override
4661 public void onShellCommand(FileDescriptor in, FileDescriptor out,
4662 FileDescriptor err, String[] args, ShellCallback callback,
4663 ResultReceiver resultReceiver) {
4664 new AccountManagerServiceShellCommand(this).exec(this, in, out, err, args,
4665 callback, resultReceiver);
4666 }
4667
Fred Quintanaa698f422009-04-08 19:14:54 -07004668 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004669 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004670 IAccountManagerResponse mResponse;
4671 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004672 final boolean mExpectActivityLaunch;
4673 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004674 final String mAccountName;
4675 // Indicates if we need to add auth details(like last credential time)
4676 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004677 // If set, we need to update the last authenticated time. This is
4678 // currently
4679 // used on
4680 // successful confirming credentials.
4681 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004682
Fred Quintana33269202009-04-20 16:05:10 -07004683 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004684 private int mNumRequestContinued = 0;
4685 private int mNumErrors = 0;
4686
Fred Quintana60307342009-03-24 22:48:12 -07004687 IAccountAuthenticator mAuthenticator = null;
4688
Fred Quintana8570f742010-02-18 10:32:54 -08004689 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004690 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004691
Amith Yamasani04e0d262012-02-14 11:50:53 -08004692 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004693 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4694 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004695 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4696 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4697 }
4698
4699 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4700 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4701 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004702 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004703 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004704 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004705 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004706 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004707 mResponse = response;
4708 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004709 mExpectActivityLaunch = expectActivityLaunch;
4710 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004711 mAccountName = accountName;
4712 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004713 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004714
Fred Quintanaa698f422009-04-08 19:14:54 -07004715 synchronized (mSessions) {
4716 mSessions.put(toString(), this);
4717 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004718 if (response != null) {
4719 try {
4720 response.asBinder().linkToDeath(this, 0 /* flags */);
4721 } catch (RemoteException e) {
4722 mResponse = null;
4723 binderDied();
4724 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004725 }
Fred Quintana60307342009-03-24 22:48:12 -07004726 }
4727
Fred Quintanaa698f422009-04-08 19:14:54 -07004728 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004729 if (mResponse == null) {
4730 // this session has already been closed
4731 return null;
4732 }
Fred Quintana60307342009-03-24 22:48:12 -07004733 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004734 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004735 return response;
4736 }
4737
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004738 /**
4739 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4740 * security policy.
4741 *
4742 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004743 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004744 * supplied entries in the system Settings app.
4745 */
tiansiminga8868bf2017-09-20 13:59:13 +08004746 protected boolean checkKeyIntent(int authUid, Intent intent) {
Jeff Sharkeyd722e782017-06-12 17:33:07 -06004747 intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4748 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4749 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4750 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004751 long bid = Binder.clearCallingIdentity();
4752 try {
4753 PackageManager pm = mContext.getPackageManager();
4754 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
tiansiminga8868bf2017-09-20 13:59:13 +08004755 if (resolveInfo == null) {
4756 return false;
4757 }
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004758 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4759 int targetUid = targetActivityInfo.applicationInfo.uid;
Dan Cashman303c4bb2018-04-10 07:41:16 -07004760 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004761 if (!isExportedSystemActivity(targetActivityInfo)
Dan Cashman303c4bb2018-04-10 07:41:16 -07004762 && !pmi.hasSignatureCapability(
4763 targetUid, authUid,
4764 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004765 String pkgName = targetActivityInfo.packageName;
4766 String activityName = targetActivityInfo.name;
4767 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4768 + "does not share a signature with the supplying authenticator (%s).";
tiansiminga8868bf2017-09-20 13:59:13 +08004769 Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
4770 return false;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004771 }
tiansiminga8868bf2017-09-20 13:59:13 +08004772 return true;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004773 } finally {
4774 Binder.restoreCallingIdentity(bid);
4775 }
4776 }
4777
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004778 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4779 String className = activityInfo.name;
4780 return "android".equals(activityInfo.packageName) &&
4781 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4782 || CantAddAccountActivity.class.getName().equals(className));
4783 }
4784
Fred Quintanaa698f422009-04-08 19:14:54 -07004785 private void close() {
4786 synchronized (mSessions) {
4787 if (mSessions.remove(toString()) == null) {
4788 // the session was already closed, so bail out now
4789 return;
4790 }
4791 }
4792 if (mResponse != null) {
4793 // stop listening for response deaths
4794 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4795
4796 // clear this so that we don't accidentally send any further results
4797 mResponse = null;
4798 }
4799 cancelTimeout();
4800 unbind();
4801 }
4802
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004803 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004804 public void binderDied() {
4805 mResponse = null;
4806 close();
4807 }
4808
4809 protected String toDebugString() {
4810 return toDebugString(SystemClock.elapsedRealtime());
4811 }
4812
4813 protected String toDebugString(long now) {
4814 return "Session: expectLaunch " + mExpectActivityLaunch
4815 + ", connected " + (mAuthenticator != null)
4816 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4817 + "/" + mNumErrors + ")"
4818 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4819 }
4820
Fred Quintana60307342009-03-24 22:48:12 -07004821 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004822 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4823 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4824 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004825 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004826 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004827 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004828 }
4829 }
4830
4831 private void unbind() {
4832 if (mAuthenticator != null) {
4833 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004834 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004835 }
4836 }
4837
Fred Quintana60307342009-03-24 22:48:12 -07004838 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004839 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004840 }
4841
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004842 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004843 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004844 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004845 try {
4846 run();
4847 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004848 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004849 "remote exception");
4850 }
Fred Quintana60307342009-03-24 22:48:12 -07004851 }
4852
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004853 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004854 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004855 mAuthenticator = null;
4856 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004857 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004858 try {
4859 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4860 "disconnected");
4861 } catch (RemoteException e) {
4862 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4863 Log.v(TAG, "Session.onServiceDisconnected: "
4864 + "caught RemoteException while responding", e);
4865 }
4866 }
Fred Quintana60307342009-03-24 22:48:12 -07004867 }
4868 }
4869
Fred Quintanab839afc2009-10-14 15:57:28 -07004870 public abstract void run() throws RemoteException;
4871
Fred Quintana60307342009-03-24 22:48:12 -07004872 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004873 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004874 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004875 try {
4876 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4877 "timeout");
4878 } catch (RemoteException e) {
4879 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4880 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4881 e);
4882 }
4883 }
Fred Quintana60307342009-03-24 22:48:12 -07004884 }
4885 }
4886
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004887 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004888 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004889 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004890 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004891 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004892 if (result != null) {
4893 boolean isSuccessfulConfirmCreds = result.getBoolean(
4894 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004895 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004896 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4897 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004898 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004899 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4900 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004901 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004902 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004903 if (needUpdate || mAuthDetailsRequired) {
4904 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4905 if (needUpdate && accountPresent) {
4906 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4907 }
4908 if (mAuthDetailsRequired) {
4909 long lastAuthenticatedTime = -1;
4910 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004911 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004912 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004913 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004914 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004915 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004916 lastAuthenticatedTime);
4917 }
4918 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004919 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004920 if (result != null
4921 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08004922 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004923 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08004924 intent)) {
4925 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
4926 "invalid intent in bundle returned");
4927 return;
4928 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004929 }
4930 if (result != null
4931 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004932 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4933 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004934 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4935 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004936 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4937 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004938 }
Fred Quintana60307342009-03-24 22:48:12 -07004939 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004940 IAccountManagerResponse response;
4941 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004942 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004943 response = mResponse;
4944 } else {
4945 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004946 }
Fred Quintana60307342009-03-24 22:48:12 -07004947 if (response != null) {
4948 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004949 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004950 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4951 Log.v(TAG, getClass().getSimpleName()
4952 + " calling onError() on response " + response);
4953 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004954 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004955 "null bundle returned");
4956 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004957 if (mStripAuthTokenFromResult) {
4958 result.remove(AccountManager.KEY_AUTHTOKEN);
4959 }
Fred Quintana56285a62010-12-02 14:20:51 -08004960 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4961 Log.v(TAG, getClass().getSimpleName()
4962 + " calling onResult() on response " + response);
4963 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004964 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4965 (intent == null)) {
4966 // All AccountManager error codes are greater than 0
4967 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4968 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4969 } else {
4970 response.onResult(result);
4971 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004972 }
Fred Quintana60307342009-03-24 22:48:12 -07004973 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004974 // if the caller is dead then there is no one to care about remote exceptions
4975 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4976 Log.v(TAG, "failure while notifying response", e);
4977 }
Fred Quintana60307342009-03-24 22:48:12 -07004978 }
4979 }
4980 }
Fred Quintana60307342009-03-24 22:48:12 -07004981
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004982 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004983 public void onRequestContinued() {
4984 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004985 }
4986
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004987 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004988 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004989 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004990 IAccountManagerResponse response = getResponseAndClose();
4991 if (response != null) {
4992 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004993 Log.v(TAG, getClass().getSimpleName()
4994 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004995 }
4996 try {
4997 response.onError(errorCode, errorMessage);
4998 } catch (RemoteException e) {
4999 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5000 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
5001 }
5002 }
5003 } else {
5004 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5005 Log.v(TAG, "Session.onError: already closed");
5006 }
Fred Quintana60307342009-03-24 22:48:12 -07005007 }
5008 }
Fred Quintanab839afc2009-10-14 15:57:28 -07005009
5010 /**
5011 * find the component name for the authenticator and initiate a bind
5012 * if no authenticator or the bind fails then return false, otherwise return true
5013 */
5014 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005015 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
5016 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
5017 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07005018 if (authenticatorInfo == null) {
5019 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5020 Log.v(TAG, "there is no authenticator for " + authenticatorType
5021 + ", bailing out");
5022 }
5023 return false;
5024 }
5025
Jeff Sharkeyce18c812016-04-27 16:00:41 -06005026 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06005027 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07005028 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
5029 + " which isn't encryption aware");
5030 return false;
5031 }
5032
Fred Quintanab839afc2009-10-14 15:57:28 -07005033 Intent intent = new Intent();
5034 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
5035 intent.setComponent(authenticatorInfo.componentName);
5036 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5037 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
5038 }
Hongming Jin8e2bfc12018-05-30 11:01:06 -07005039 int flags = Context.BIND_AUTO_CREATE;
5040 if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
5041 flags |= Context.BIND_ALLOW_INSTANT;
5042 }
5043 if (!mContext.bindServiceAsUser(intent, this, flags, UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07005044 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5045 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
5046 }
5047 return false;
5048 }
5049
Fred Quintanab839afc2009-10-14 15:57:28 -07005050 return true;
5051 }
Fred Quintana60307342009-03-24 22:48:12 -07005052 }
5053
Svet Ganov5d09c992016-09-07 09:57:41 -07005054 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07005055 MessageHandler(Looper looper) {
5056 super(looper);
5057 }
Costin Manolache3348f142009-09-29 18:58:36 -07005058
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07005059 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005060 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07005061 switch (msg.what) {
5062 case MESSAGE_TIMED_OUT:
5063 Session session = (Session)msg.obj;
5064 session.onTimedOut();
5065 break;
5066
Amith Yamasani5be347b2013-03-31 17:44:31 -07005067 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00005068 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07005069 break;
5070
Fred Quintana60307342009-03-24 22:48:12 -07005071 default:
5072 throw new IllegalStateException("unhandled message: " + msg.what);
5073 }
5074 }
5075 }
5076
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005077 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005078 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005079 }
5080
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005081 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005082 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005083 }
5084
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005085 /*
5086 * This function receives an opened writable database.
5087 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005088 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005089 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005090 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005091 }
5092
5093 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005094 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005095 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005096 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005097 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005098
5099 class LogRecordTask implements Runnable {
5100 private final String action;
5101 private final String tableName;
5102 private final long accountId;
5103 private final UserAccounts userAccount;
5104 private final int callingUid;
5105 private final long userDebugDbInsertionPoint;
5106
5107 LogRecordTask(final String action,
5108 final String tableName,
5109 final long accountId,
5110 final UserAccounts userAccount,
5111 final int callingUid,
5112 final long userDebugDbInsertionPoint) {
5113 this.action = action;
5114 this.tableName = tableName;
5115 this.accountId = accountId;
5116 this.userAccount = userAccount;
5117 this.callingUid = callingUid;
5118 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5119 }
5120
Andrew Scullc7770d62017-05-22 17:49:58 +01005121 @Override
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005122 public void run() {
Dmitry Dementyev47443192018-10-24 13:31:59 -07005123 synchronized (userAccount.accountsDb.mDebugStatementLock) {
5124 SQLiteStatement logStatement = userAccount.accountsDb.getStatementForLogging();
5125 if (logStatement == null) {
5126 return; // Can't log.
5127 }
5128 logStatement.bindLong(1, accountId);
5129 logStatement.bindString(2, action);
5130 logStatement.bindString(3, mDateFormat.format(new Date()));
5131 logStatement.bindLong(4, callingUid);
5132 logStatement.bindString(5, tableName);
5133 logStatement.bindLong(6, userDebugDbInsertionPoint);
5134 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 }
Tetsutoki Shiozawabe2d96a2017-10-24 18:44:00 +09005144 }
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005145 }
5146 }
Dmitry Dementyev47443192018-10-24 13:31:59 -07005147 long insertionPoint = userAccount.accountsDb.reserveDebugDbInsertionPoint();
5148 if (insertionPoint != -1) {
5149 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5150 callingUid, insertionPoint);
5151 mHandler.post(logTask);
5152 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005153 }
5154
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005155 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07005156 return asBinder();
5157 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005158
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005159 /**
5160 * Searches array of arguments for the specified string
5161 * @param args array of argument strings
5162 * @param value value to search for
5163 * @return true if the value is contained in the array
5164 */
5165 private static boolean scanArgs(String[] args, String value) {
5166 if (args != null) {
5167 for (String arg : args) {
5168 if (value.equals(arg)) {
5169 return true;
5170 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005171 }
5172 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005173 return false;
5174 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005175
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005176 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005177 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005178 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005179 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005180 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07005181
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005182 final List<UserInfo> users = getUserManager().getUsers();
5183 for (UserInfo user : users) {
5184 ipw.println("User " + user + ":");
5185 ipw.increaseIndent();
5186 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5187 ipw.println();
5188 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08005189 }
5190 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005191
Amith Yamasani04e0d262012-02-14 11:50:53 -08005192 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5193 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005194 if (isCheckinRequest) {
5195 // This is a checkin request. *Only* upload the account types and the count of
5196 // each.
5197 synchronized (userAccounts.dbLock) {
5198 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5199 }
5200 } else {
5201 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5202 Process.SYSTEM_UID, null /* packageName */, false);
5203 fout.println("Accounts: " + accounts.length);
5204 for (Account account : accounts) {
Makoto Onukib9425222019-01-23 11:35:43 -08005205 fout.println(" " + account.toString());
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005206 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005207
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005208 // Add debug information.
5209 fout.println();
5210 synchronized (userAccounts.dbLock) {
5211 userAccounts.accountsDb.dumpDebugTable(fout);
5212 }
5213 fout.println();
5214 synchronized (mSessions) {
5215 final long now = SystemClock.elapsedRealtime();
5216 fout.println("Active Sessions: " + mSessions.size());
5217 for (Session session : mSessions.values()) {
5218 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005219 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005220 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005221
5222 fout.println();
5223 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Tony Mak6d14d772017-07-13 17:49:46 +08005224
5225 boolean isUserUnlocked;
5226 synchronized (mUsers) {
5227 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
5228 }
5229 // Following logs are printed only when user is unlocked.
5230 if (!isUserUnlocked) {
5231 return;
5232 }
5233 fout.println();
5234 synchronized (userAccounts.dbLock) {
5235 Map<Account, Map<String, Integer>> allVisibilityValues =
5236 userAccounts.accountsDb.findAllVisibilityValues();
5237 fout.println("Account visibility:");
5238 for (Account account : allVisibilityValues.keySet()) {
5239 fout.println(" " + account.name);
5240 Map<String, Integer> visibilities = allVisibilityValues.get(account);
5241 for (Entry<String, Integer> entry : visibilities.entrySet()) {
5242 fout.println(" " + entry.getKey() + ", " + entry.getValue());
5243 }
5244 }
5245 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005246 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005247 }
5248
Amith Yamasani04e0d262012-02-14 11:50:53 -08005249 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005250 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005251 long identityToken = clearCallingIdentity();
5252 try {
5253 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5254 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5255 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005256
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005257 if (intent.getComponent() != null &&
5258 GrantCredentialsPermissionActivity.class.getName().equals(
5259 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005260 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005261 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005262 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04005263 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5264 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005265
Fred Quintana33f889a2009-09-14 17:31:26 -07005266 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005267 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05005268 Notification n =
5269 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005270 .setWhen(0)
5271 .setSmallIcon(android.R.drawable.stat_sys_warning)
5272 .setColor(contextForUser.getColor(
5273 com.android.internal.R.color.system_notification_accent_color))
5274 .setContentTitle(String.format(notificationTitleFormat, account.name))
5275 .setContentText(message)
5276 .setContentIntent(PendingIntent.getActivityAsUser(
5277 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005278 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005279 .build();
Chris Wren717a8812017-03-31 15:34:39 -04005280 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005281 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005282 } finally {
5283 restoreCallingIdentity(identityToken);
5284 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005285 }
5286
Chris Wren717a8812017-03-31 15:34:39 -04005287 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005288 String packageName, int userId) {
5289 final long token = clearCallingIdentity();
5290 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005291 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005292 try {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005293 // The calling uid must match either the package or op package, so use an op
5294 // package that matches the cleared calling identity.
5295 notificationManager.enqueueNotificationWithTag(packageName, "android",
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04005296 id.mTag, id.mId, notification, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005297 } catch (RemoteException e) {
5298 /* ignore - local call */
5299 }
5300 } finally {
5301 Binder.restoreCallingIdentity(token);
5302 }
Fred Quintana56285a62010-12-02 14:20:51 -08005303 }
5304
Chris Wren717a8812017-03-31 15:34:39 -04005305 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005306 cancelNotification(id, mContext.getPackageName(), user);
5307 }
5308
Chris Wren717a8812017-03-31 15:34:39 -04005309 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005310 long identityToken = clearCallingIdentity();
5311 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005312 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04005313 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005314 } catch (RemoteException e) {
5315 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005316 } finally {
5317 restoreCallingIdentity(identityToken);
5318 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005319 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005320
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005321 private boolean isPermittedForPackage(String packageName, int uid, int userId,
5322 String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005323 final long identity = Binder.clearCallingIdentity();
5324 try {
5325 IPackageManager pm = ActivityThread.getPackageManager();
5326 for (String perm : permissions) {
5327 if (pm.checkPermission(perm, packageName, userId)
5328 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005329 // Checks runtime permission revocation.
5330 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005331 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005332 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5333 return true;
5334 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005335 }
5336 }
5337 } catch (RemoteException e) {
5338 /* ignore - local call */
5339 } finally {
5340 Binder.restoreCallingIdentity(identity);
5341 }
5342 return false;
5343 }
5344
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005345 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5346 for (String perm : permissions) {
5347 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5348 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5349 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5350 }
5351 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005352 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005353 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5354 return true;
5355 }
5356 }
5357 }
5358 return false;
5359 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005360
Amith Yamasani67df64b2012-12-14 12:09:36 -08005361 private int handleIncomingUser(int userId) {
5362 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005363 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005364 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5365 } catch (RemoteException re) {
5366 // Shouldn't happen, local.
5367 }
5368 return userId;
5369 }
5370
Christopher Tateccbf84f2013-05-08 15:25:41 -07005371 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005372 String[] packages;
5373 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005374 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005375 packages = mPackageManager.getPackagesForUid(callingUid);
sunjian9ae597b62017-08-14 15:45:04 -07005376 if (packages == null) {
5377 Log.d(TAG, "No packages for callingUid " + callingUid);
Fred Quintana7be59642009-08-24 18:29:25 -07005378 return false;
5379 }
sunjian9ae597b62017-08-14 15:45:04 -07005380 for (String name : packages) {
5381 try {
5382 PackageInfo packageInfo =
5383 mPackageManager.getPackageInfo(name, 0 /* flags */);
5384 if (packageInfo != null
5385 && (packageInfo.applicationInfo.privateFlags
5386 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
5387 return true;
5388 }
5389 } catch (PackageManager.NameNotFoundException e) {
5390 Log.d(TAG, "Package not found " + e.getMessage());
5391 }
5392 }
5393 } finally {
5394 Binder.restoreCallingIdentity(identityToken);
Fred Quintana7be59642009-08-24 18:29:25 -07005395 }
5396 return false;
5397 }
5398
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005399 private boolean permissionIsGranted(
5400 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005401 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5402 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5403 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5404 }
5405 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005406 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005407
5408 if (isPrivileged(callerUid)) {
5409 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5410 Log.v(TAG, "Access to " + account + " granted calling uid "
5411 + callerUid + " privileged");
5412 }
5413 return true;
5414 }
5415 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5416 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5417 Log.v(TAG, "Access to " + account + " granted calling uid "
5418 + callerUid + " manages the account");
5419 }
5420 return true;
5421 }
5422 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5423 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5424 Log.v(TAG, "Access to " + account + " granted calling uid "
5425 + callerUid + " user granted access");
5426 }
5427 return true;
5428 }
5429
5430 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5431 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5432 }
5433
5434 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005435 }
5436
Svetoslavf3f02ac2015-09-08 14:36:35 -07005437 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5438 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005439 if (accountType == null) {
5440 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005441 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005442 return getTypesVisibleToCaller(callingUid, userId,
5443 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005444 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005445 }
5446
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005447 // Method checks visibility for applications targeing API level below {@link
5448 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005449 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005450 private boolean checkGetAccountsPermission(String packageName, int uid, int userId) {
5451 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005452 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5453 }
5454
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005455 private boolean checkReadContactsPermission(String packageName, int uid, int userId) {
5456 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS);
5457 }
5458
5459 // Heuristic to check that account type may be associated with some contacts data and
5460 // therefore READ_CONTACTS permission grants the access to account by default.
5461 private boolean accountTypeManagesContacts(String accountType, int userId) {
5462 if (accountType == null) {
5463 return false;
5464 }
5465 long identityToken = Binder.clearCallingIdentity();
5466 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5467 try {
5468 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5469 } finally {
5470 Binder.restoreCallingIdentity(identityToken);
5471 }
5472 // Check contacts related permissions for authenticator.
5473 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5474 : serviceInfos) {
5475 if (accountType.equals(serviceInfo.type.type)) {
5476 return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId,
5477 Manifest.permission.WRITE_CONTACTS);
5478 }
5479 }
5480 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005481 }
5482
5483 /**
5484 * Method checks package uid and signature with Authenticator which manages accountType.
5485 *
5486 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5487 * SIGNATURE_CHECK_MISMATCH otherwise.
5488 */
5489 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5490 if (accountType == null) {
5491 return SIGNATURE_CHECK_MISMATCH;
5492 }
5493
5494 long identityToken = Binder.clearCallingIdentity();
5495 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5496 try {
5497 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5498 } finally {
5499 Binder.restoreCallingIdentity(identityToken);
5500 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005501 // Check for signature match with Authenticator.LocalServices.getService(PackageManagerInternal.class);
5502 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005503 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5504 : serviceInfos) {
5505 if (accountType.equals(serviceInfo.type.type)) {
5506 if (serviceInfo.uid == callingUid) {
5507 return SIGNATURE_CHECK_UID_MATCH;
5508 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005509 if (pmi.hasSignatureCapability(
5510 serviceInfo.uid, callingUid,
5511 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005512 return SIGNATURE_CHECK_MATCH;
5513 }
5514 }
5515 }
5516 return SIGNATURE_CHECK_MISMATCH;
5517 }
5518
5519 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005520 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5521 if (accountType == null) {
5522 return false;
5523 } else {
5524 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5525 }
5526 }
5527
Svetoslavf3f02ac2015-09-08 14:36:35 -07005528 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5529 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005530 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005531 }
5532
5533 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005534 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005535 }
5536
5537 private List<String> getTypesForCaller(
5538 int callingUid, int userId, boolean isOtherwisePermitted) {
5539 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005540 long identityToken = Binder.clearCallingIdentity();
5541 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5542 try {
5543 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5544 } finally {
5545 Binder.restoreCallingIdentity(identityToken);
5546 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005547
5548 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005549 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005550 serviceInfos) {
Dan Cashman303c4bb2018-04-10 07:41:16 -07005551 if (isOtherwisePermitted || pmi.hasSignatureCapability(
5552 serviceInfo.uid, callingUid,
5553 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005554 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005555 }
5556 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005557 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005558 }
5559
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005560 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5561 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5562 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5563 if (account.name.equals(accountName)) {
5564 return true;
5565 }
5566 }
5567 }
5568 return false;
5569 }
5570
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005571 private static void checkManageUsersPermission(String message) {
5572 if (ActivityManager.checkComponentPermission(
5573 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5574 != PackageManager.PERMISSION_GRANTED) {
5575 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5576 }
5577 }
5578
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005579 private static void checkManageOrCreateUsersPermission(String message) {
5580 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5581 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5582 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5583 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5584 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5585 + message);
5586 }
5587 }
5588
Amith Yamasani04e0d262012-02-14 11:50:53 -08005589 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5590 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005591 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005592 return true;
5593 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005594 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005595 synchronized (accounts.dbLock) {
5596 synchronized (accounts.cacheLock) {
5597 long grantsCount;
5598 if (authTokenType != null) {
5599 grantsCount = accounts.accountsDb
5600 .findMatchingGrantsCount(callerUid, authTokenType, account);
5601 } else {
5602 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5603 account);
5604 }
5605 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005606
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005607 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5608 // TODO: Skip this check when running automated tests. Replace this
5609 // with a more general solution.
Hui Yu139c2482018-08-10 15:37:51 -07005610 Log.d(TAG, "no credentials permission for usage of "
5611 + account.toSafeString() + ", "
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005612 + authTokenType + " by uid " + callerUid
5613 + " but ignoring since device is in test harness.");
5614 return true;
5615 }
5616 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005617 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005618 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005619 }
5620
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005621 private boolean isSystemUid(int callingUid) {
5622 String[] packages = null;
5623 long ident = Binder.clearCallingIdentity();
5624 try {
5625 packages = mPackageManager.getPackagesForUid(callingUid);
Alex Chau81a47cd2018-01-02 16:49:14 +00005626 if (packages != null) {
5627 for (String name : packages) {
5628 try {
5629 PackageInfo packageInfo =
5630 mPackageManager.getPackageInfo(name, 0 /* flags */);
5631 if (packageInfo != null
5632 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5633 != 0) {
5634 return true;
5635 }
5636 } catch (NameNotFoundException e) {
5637 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5638 }
5639 }
5640 } else {
5641 Log.w(TAG, "No known packages with uid " + callingUid);
5642 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005643 } finally {
5644 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005645 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005646 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005647 }
5648
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005649 /** Succeeds if any of the specified permissions are granted. */
5650 private void checkReadAccountsPermitted(
5651 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005652 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005653 int userId,
5654 String opPackageName) {
5655 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005656 String msg = String.format(
5657 "caller uid %s cannot access %s accounts",
5658 callingUid,
5659 accountType);
5660 Log.w(TAG, " " + msg);
5661 throw new SecurityException(msg);
5662 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005663 }
5664
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005665 private boolean canUserModifyAccounts(int userId, int callingUid) {
5666 // the managing app can always modify accounts
5667 if (isProfileOwner(callingUid)) {
5668 return true;
5669 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005670 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5671 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5672 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005673 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005674 return true;
5675 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005676
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005677 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5678 // the managing app can always modify accounts
5679 if (isProfileOwner(callingUid)) {
5680 return true;
5681 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005682 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5683 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005684 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005685 if (typesArray == null) {
5686 return true;
5687 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005688 for (String forbiddenType : typesArray) {
5689 if (forbiddenType.equals(accountType)) {
5690 return false;
5691 }
5692 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005693 return true;
5694 }
5695
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005696 private boolean isProfileOwner(int uid) {
5697 final DevicePolicyManagerInternal dpmi =
5698 LocalServices.getService(DevicePolicyManagerInternal.class);
5699 return (dpmi != null)
5700 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5701 }
5702
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005703 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005704 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5705 throws RemoteException {
5706 final int callingUid = getCallingUid();
5707
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005708 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005709 throw new SecurityException();
5710 }
5711
5712 if (value) {
5713 grantAppPermission(account, authTokenType, uid);
5714 } else {
5715 revokeAppPermission(account, authTokenType, uid);
5716 }
5717 }
5718
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005719 /**
5720 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5721 * <p>
5722 * Although this is public it can only be accessed via the AccountManagerService object
5723 * which is in the system. This means we don't need to protect it with permissions.
5724 * @hide
5725 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005726 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005727 if (account == null || authTokenType == null) {
5728 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005729 return;
5730 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005731 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005732 synchronized (accounts.dbLock) {
5733 synchronized (accounts.cacheLock) {
5734 long accountId = accounts.accountsDb.findDeAccountId(account);
5735 if (accountId >= 0) {
5736 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5737 }
5738 cancelNotification(
5739 getCredentialPermissionNotificationId(account, authTokenType, uid),
5740 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005741
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005742 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5743 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005744 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005745
5746 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5747 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5748 : mAppPermissionChangeListeners) {
5749 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5750 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005751 }
5752
5753 /**
5754 * Don't allow callers with the given uid permission to get credentials for
5755 * account/authTokenType.
5756 * <p>
5757 * Although this is public it can only be accessed via the AccountManagerService object
5758 * which is in the system. This means we don't need to protect it with permissions.
5759 * @hide
5760 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005761 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005762 if (account == null || authTokenType == null) {
5763 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005764 return;
5765 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005766 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005767 synchronized (accounts.dbLock) {
5768 synchronized (accounts.cacheLock) {
5769 accounts.accountsDb.beginTransaction();
5770 try {
5771 long accountId = accounts.accountsDb.findDeAccountId(account);
5772 if (accountId >= 0) {
5773 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5774 accountId, authTokenType, uid);
5775 accounts.accountsDb.setTransactionSuccessful();
5776 }
5777 } finally {
5778 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005779 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005780
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005781 cancelNotification(
5782 getCredentialPermissionNotificationId(account, authTokenType, uid),
5783 UserHandle.of(accounts.userId));
5784 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005785 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005786
5787 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5788 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5789 : mAppPermissionChangeListeners) {
5790 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5791 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005792 }
Fred Quintana56285a62010-12-02 14:20:51 -08005793
Amith Yamasani04e0d262012-02-14 11:50:53 -08005794 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5795 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005796 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005797 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005798 for (Account curAccount : oldAccountsForType) {
5799 if (!curAccount.equals(account)) {
5800 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005801 }
5802 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005803 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005804 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005805 } else {
5806 Account[] newAccountsForType = new Account[newAccountsList.size()];
5807 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005808 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005809 }
Fred Quintana56285a62010-12-02 14:20:51 -08005810 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005811 accounts.userDataCache.remove(account);
5812 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005813 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005814 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005815 }
5816
5817 /**
5818 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005819 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5820 * processes and if you will return this account to apps you should return the result.
5821 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005822 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005823 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005824 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005825 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5826 Account[] newAccountsForType = new Account[oldLength + 1];
5827 if (accountsForType != null) {
5828 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005829 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005830 String token = account.getAccessId() != null ? account.getAccessId()
5831 : UUID.randomUUID().toString();
5832 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005833 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005834 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005835 }
5836
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005837 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005838 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005839 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005840 String visibilityFilterPackage = callingPackage;
5841 if (visibilityFilterPackage == null) {
5842 visibilityFilterPackage = getPackageNameForUid(callingUid);
5843 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005844 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005845 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005846 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005847 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5848 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5849 || (includeManagedNotVisible
5850 && (visibility
5851 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5852 firstPass.put(account, visibility);
5853 }
5854 }
5855 Map<Account, Integer> secondPass =
5856 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5857
5858 Account[] filtered = new Account[secondPass.size()];
5859 filtered = secondPass.keySet().toArray(filtered);
5860 return filtered;
5861 }
5862
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005863 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005864 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005865 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005866 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005867 // first part is to filter shared accounts.
5868 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005869 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005870 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005871 return unfiltered;
5872 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005873 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005874 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005875 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005876 if (packages == null) {
5877 packages = new String[] {};
5878 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005879 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005880 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005881 // This might be a temporary way to specify a visible list
5882 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005883 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5884 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005885 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005886 return unfiltered;
5887 }
5888 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005889 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005890 if (ArrayUtils.isEmpty(sharedAccounts)) {
5891 return unfiltered;
5892 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005893 String requiredAccountType = "";
5894 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005895 // If there's an explicit callingPackage specified, check if that package
5896 // opted in to see restricted accounts.
5897 if (callingPackage != null) {
5898 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005899 if (pi != null && pi.restrictedAccountType != null) {
5900 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005901 }
5902 } else {
5903 // Otherwise check if the callingUid has a package that has opted in
5904 for (String packageName : packages) {
5905 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5906 if (pi != null && pi.restrictedAccountType != null) {
5907 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005908 break;
5909 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005910 }
5911 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005912 } catch (NameNotFoundException e) {
5913 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005914 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005915 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005916 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5917 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005918 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005919 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005920 } else {
5921 boolean found = false;
5922 for (Account shared : sharedAccounts) {
5923 if (shared.equals(account)) {
5924 found = true;
5925 break;
5926 }
5927 }
5928 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005929 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005930 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005931 }
5932 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005933 return filtered;
5934 } else {
5935 return unfiltered;
5936 }
5937 }
5938
Amith Yamasani27db4682013-03-30 17:07:47 -07005939 /*
5940 * packageName can be null. If not null, it should be used to filter out restricted accounts
5941 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005942 *
5943 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5944 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005945 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005946 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005947 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005948 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005949 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5950 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005951 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005952 Account[] accounts;
5953 synchronized (userAccounts.cacheLock) {
5954 accounts = userAccounts.accountCache.get(accountType);
5955 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005956 if (accounts == null) {
5957 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005958 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005959 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5960 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005961 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005962 } else {
5963 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005964 Account[] accountsArray;
5965 synchronized (userAccounts.cacheLock) {
5966 for (Account[] accounts : userAccounts.accountCache.values()) {
5967 totalLength += accounts.length;
5968 }
5969 if (totalLength == 0) {
5970 return EMPTY_ACCOUNT_ARRAY;
5971 }
5972 accountsArray = new Account[totalLength];
5973 totalLength = 0;
5974 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5975 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5976 accountsOfType.length);
5977 totalLength += accountsOfType.length;
5978 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005979 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005980 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005981 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005982 }
5983 }
5984
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005985 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005986 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005987 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005988 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005989 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005990 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005991 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005992 }
5993 if (value == null) {
5994 userDataForAccount.remove(key);
5995 } else {
5996 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005997 }
5998 }
5999
Carlos Valdivia91979be2015-05-22 14:11:35 -07006000 protected String readCachedTokenInternal(
6001 UserAccounts accounts,
6002 Account account,
6003 String tokenType,
6004 String callingPackage,
6005 byte[] pkgSigDigest) {
Dmitry Dementyev18f0ca92017-06-12 17:56:47 -07006006 synchronized (accounts.cacheLock) {
6007 return accounts.accountTokenCaches.get(
6008 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07006009 }
6010 }
6011
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006012 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006013 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08006014 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006015 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006016 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07006017 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08006018 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006019 }
6020 if (value == null) {
6021 authTokensForAccount.remove(key);
6022 } else {
6023 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08006024 }
6025 }
6026
Amith Yamasani04e0d262012-02-14 11:50:53 -08006027 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
6028 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006029 // Fast path - check if account is already cached
6030 synchronized (accounts.cacheLock) {
6031 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6032 if (authTokensForAccount != null) {
6033 return authTokensForAccount.get(authTokenType);
6034 }
6035 }
6036 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07006037 synchronized (accounts.dbLock) {
6038 synchronized (accounts.cacheLock) {
6039 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6040 if (authTokensForAccount == null) {
6041 // need to populate the cache for this account
6042 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6043 accounts.authTokenCache.put(account, authTokensForAccount);
6044 }
6045 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08006046 }
Fred Quintana56285a62010-12-02 14:20:51 -08006047 }
6048 }
6049
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006050 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
6051 Map<String, String> userDataForAccount;
6052 // Fast path - check if data is already cached
6053 synchronized (accounts.cacheLock) {
6054 userDataForAccount = accounts.userDataCache.get(account);
6055 }
6056 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00006057 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006058 synchronized (accounts.dbLock) {
6059 synchronized (accounts.cacheLock) {
6060 userDataForAccount = accounts.userDataCache.get(account);
6061 if (userDataForAccount == null) {
6062 // need to populate the cache for this account
6063 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6064 accounts.userDataCache.put(account, userDataForAccount);
6065 }
6066 }
6067 }
Fred Quintana56285a62010-12-02 14:20:51 -08006068 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00006069 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08006070 }
6071
Kenny Guy07ad8dc2014-09-01 20:56:12 +01006072 private Context getContextForUser(UserHandle user) {
6073 try {
6074 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
6075 } catch (NameNotFoundException e) {
6076 // Default to mContext, not finding the package system is running as is unlikely.
6077 return mContext;
6078 }
6079 }
Sandra Kwan78812282015-11-04 11:19:47 -08006080
6081 private void sendResponse(IAccountManagerResponse response, Bundle result) {
6082 try {
6083 response.onResult(result);
6084 } catch (RemoteException e) {
6085 // if the caller is dead then there is no one to care about remote
6086 // exceptions
6087 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6088 Log.v(TAG, "failure while notifying response", e);
6089 }
6090 }
6091 }
6092
6093 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6094 String errorMessage) {
6095 try {
6096 response.onError(errorCode, errorMessage);
6097 } catch (RemoteException e) {
6098 // if the caller is dead then there is no one to care about remote
6099 // exceptions
6100 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6101 Log.v(TAG, "failure while notifying response", e);
6102 }
6103 }
6104 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006105
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006106 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07006107 private final Object mLock = new Object();
6108
6109 @GuardedBy("mLock")
6110 private AccountManagerBackupHelper mBackupHelper;
6111
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006112 @Override
6113 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6114 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6115 if (account == null) {
6116 Slog.w(TAG, "account cannot be null");
6117 return;
6118 }
6119 if (packageName == null) {
6120 Slog.w(TAG, "packageName cannot be null");
6121 return;
6122 }
6123 if (userId < UserHandle.USER_SYSTEM) {
6124 Slog.w(TAG, "user id must be concrete");
6125 return;
6126 }
6127 if (callback == null) {
6128 Slog.w(TAG, "callback cannot be null");
6129 return;
6130 }
6131
Dmitry Dementyev7b3ea132017-05-10 12:45:02 -07006132 int visibility =
6133 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6134 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6135 Slog.w(TAG, "requestAccountAccess: account is hidden");
6136 return;
6137 }
6138
Svet Ganovf6d424f12016-09-20 20:18:53 -07006139 if (AccountManagerService.this.hasAccountAccess(account, packageName,
6140 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006141 Bundle result = new Bundle();
6142 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6143 callback.sendResult(result);
6144 return;
6145 }
6146
6147 final int uid;
6148 try {
Dmitry Dementyev940b7602018-10-09 16:40:06 -07006149 long identityToken = clearCallingIdentity();
6150 try {
6151 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6152 } finally {
6153 restoreCallingIdentity(identityToken);
6154 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006155 } catch (NameNotFoundException e) {
6156 Slog.e(TAG, "Unknown package " + packageName);
6157 return;
6158 }
6159
6160 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006161 final UserAccounts userAccounts;
6162 synchronized (mUsers) {
6163 userAccounts = mUsers.get(userId);
6164 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04006165 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006166 doNotification(userAccounts, account, null, intent, packageName, userId);
6167 }
6168
6169 @Override
6170 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6171 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6172 mAppPermissionChangeListeners.add(listener);
6173 }
6174
6175 @Override
6176 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6177 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006178 }
Svet Ganov5d09c992016-09-07 09:57:41 -07006179
6180 @Override
6181 public byte[] backupAccountAccessPermissions(int userId) {
6182 synchronized (mLock) {
6183 if (mBackupHelper == null) {
6184 mBackupHelper = new AccountManagerBackupHelper(
6185 AccountManagerService.this, this);
6186 }
6187 return mBackupHelper.backupAccountAccessPermissions(userId);
6188 }
6189 }
6190
6191 @Override
6192 public void restoreAccountAccessPermissions(byte[] data, int userId) {
6193 synchronized (mLock) {
6194 if (mBackupHelper == null) {
6195 mBackupHelper = new AccountManagerBackupHelper(
6196 AccountManagerService.this, this);
6197 }
6198 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6199 }
6200 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006201 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07006202
6203 @VisibleForTesting
6204 static class Injector {
6205 private final Context mContext;
6206
6207 public Injector(Context context) {
6208 mContext = context;
6209 }
6210
6211 Looper getMessageHandlerLooper() {
6212 ServiceThread serviceThread = new ServiceThread(TAG,
6213 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6214 serviceThread.start();
6215 return serviceThread.getLooper();
6216 }
6217
6218 Context getContext() {
6219 return mContext;
6220 }
6221
6222 void addLocalService(AccountManagerInternal service) {
6223 LocalServices.addService(AccountManagerInternal.class, service);
6224 }
6225
6226 String getDeDatabaseName(int userId) {
6227 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6228 AccountsDb.DE_DATABASE_NAME);
6229 return databaseFile.getPath();
6230 }
6231
6232 String getCeDatabaseName(int userId) {
6233 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6234 AccountsDb.CE_DATABASE_NAME);
6235 return databaseFile.getPath();
6236 }
6237
6238 String getPreNDatabaseName(int userId) {
6239 File systemDir = Environment.getDataSystemDirectory();
6240 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6241 PRE_N_DATABASE_NAME);
6242 if (userId == 0) {
6243 // Migrate old file, if it exists, to the new location.
6244 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006245 // accidentally created in the old location,
6246 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07006247 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6248 if (oldFile.exists() && !databaseFile.exists()) {
6249 // Check for use directory; create if it doesn't exist, else renameTo will fail
6250 File userDir = Environment.getUserSystemDirectory(userId);
6251 if (!userDir.exists()) {
6252 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006253 throw new IllegalStateException(
6254 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006255 }
6256 }
6257 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006258 throw new IllegalStateException(
6259 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006260 }
6261 }
6262 }
6263 return databaseFile.getPath();
6264 }
6265
6266 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6267 return new AccountAuthenticatorCache(mContext);
6268 }
6269
6270 INotificationManager getNotificationManager() {
6271 return NotificationManager.getService();
6272 }
6273 }
Chris Wren717a8812017-03-31 15:34:39 -04006274
Andrew Scullc7770d62017-05-22 17:49:58 +01006275 private static class NotificationId {
Chris Wren717a8812017-03-31 15:34:39 -04006276 final String mTag;
6277 private final int mId;
6278
6279 NotificationId(String tag, int type) {
6280 mTag = tag;
6281 mId = type;
6282 }
6283 }
Fred Quintana60307342009-03-24 22:48:12 -07006284}