blob: b2797f9c7a1792087a7ee4473210438ff9a3fc4b [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;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080082import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070083import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070084import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070085import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070086import android.text.TextUtils;
87import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070088import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070089import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080090import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070091import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070092
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070093import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070094import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070095import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070096import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040097import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050098import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080099import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600100import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800101import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -0700102import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +0000103import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700104import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600105import com.android.server.SystemService;
106
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700107import com.google.android.collect.Lists;
108import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700109
Oscar Montemayora8529f62009-11-18 10:14:20 -0800110import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700111import java.io.FileDescriptor;
112import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800113import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700114import java.security.MessageDigest;
115import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700116import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700117import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800118import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700119import java.util.Collection;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700120import java.util.Collections;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700121import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700122import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700123import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800124import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700125import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800126import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800127import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700128import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700129import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700130import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700131import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700132import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700133
Fred Quintana60307342009-03-24 22:48:12 -0700134/**
135 * A system service that provides account, password, and authtoken management for all
136 * accounts on the device. Some of these calls are implemented with the help of the corresponding
137 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
138 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700139 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700140 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700141 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700142public class AccountManagerService
143 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800144 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700145 private static final String TAG = "AccountManagerService";
146
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600147 public static class Lifecycle extends SystemService {
148 private AccountManagerService mService;
149
150 public Lifecycle(Context context) {
151 super(context);
152 }
153
154 @Override
155 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700156 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600157 publishBinderService(Context.ACCOUNT_SERVICE, mService);
158 }
159
160 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600161 public void onUnlockUser(int userHandle) {
162 mService.onUnlockUser(userHandle);
163 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700164
165 @Override
Fyodor Kupolovce25ed22017-05-04 11:44:31 -0700166 public void onStopUser(int userHandle) {
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700167 Slog.i(TAG, "onStopUser " + userHandle);
168 mService.purgeUserData(userHandle);
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700169 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600170 }
171
Svet Ganov5d09c992016-09-07 09:57:41 -0700172 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700173
Fred Quintana56285a62010-12-02 14:20:51 -0800174 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700175 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700176 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700177 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800178
Svet Ganov5d09c992016-09-07 09:57:41 -0700179 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700180
Fred Quintana60307342009-03-24 22:48:12 -0700181 // Messages that can be sent on mHandler
182 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700183 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700184
Fred Quintana56285a62010-12-02 14:20:51 -0800185 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700186 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700187 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800188
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800189 private static final int SIGNATURE_CHECK_MISMATCH = 0;
190 private static final int SIGNATURE_CHECK_MATCH = 1;
191 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
192
Carlos Valdivia91979be2015-05-22 14:11:35 -0700193 static {
194 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800195 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
196 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700197 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700198
199 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700200
Amith Yamasani04e0d262012-02-14 11:50:53 -0800201 static class UserAccounts {
202 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700203 final AccountsDb accountsDb;
Chris Wren717a8812017-03-31 15:34:39 -0400204 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
205 credentialsPermissionNotificationIds = new HashMap<>();
206 private final HashMap<Account, NotificationId> signinRequiredNotificationIds
207 = new HashMap<>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700208 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700209 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800210 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700211 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800212 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700213 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
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>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700216 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700217 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700218 /** protected by the {@link #cacheLock} */
219 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700220
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700221 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700222 * type -> (packageName -> number of active receivers)
223 * type == null is used to get notifications about all account types
224 */
225 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800226
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700227 /**
228 * protected by the {@link #cacheLock}
229 *
230 * Caches the previous names associated with an account. Previous names
231 * should be cached because we expect that when an Account is renamed,
232 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
233 * want to know if the accounts they care about have been renamed.
234 *
235 * The previous names are wrapped in an {@link AtomicReference} so that
236 * we can distinguish between those accounts with no previous names and
237 * those whose previous names haven't been cached (yet).
238 */
239 private final HashMap<Account, AtomicReference<String>> previousNameCache =
240 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800241
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700242 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700243 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700244
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700245 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800246 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700247 synchronized (dbLock) {
248 synchronized (cacheLock) {
249 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
250 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800251 }
252 }
253 }
254
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700255 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600256 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700257 // Not thread-safe. Only use in synchronized context
258 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700259 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
260 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800261
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700262 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700263 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700264
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700265 /**
266 * This should only be called by system code. One should only call this after the service
267 * has started.
268 * @return a reference to the AccountManagerService instance
269 * @hide
270 */
271 public static AccountManagerService getSingleton() {
272 return sThis.get();
273 }
Fred Quintana60307342009-03-24 22:48:12 -0700274
Fyodor Kupolovda993802016-09-21 14:47:10 -0700275 public AccountManagerService(Injector injector) {
276 mInjector = injector;
277 mContext = injector.getContext();
278 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700279 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700280 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
281 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800282 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700283
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700284 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800285
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800286 IntentFilter intentFilter = new IntentFilter();
287 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
288 intentFilter.addDataScheme("package");
289 mContext.registerReceiver(new BroadcastReceiver() {
290 @Override
291 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700292 // Don't delete accounts when updating a authenticator's
293 // package.
294 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700295 /* Purging data requires file io, don't block the main thread. This is probably
296 * less than ideal because we are introducing a race condition where old grants
297 * could be exercised until they are purged. But that race condition existed
298 * anyway with the broadcast receiver.
299 *
300 * Ideally, we would completely clear the cache, purge data from the database,
301 * and then rebuild the cache. All under the cache lock. But that change is too
302 * large at this point.
303 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800304 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700305 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700306 @Override
307 public void run() {
308 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800309 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800310 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700311 }
312 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700313 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700314 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800315 }
316 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800317
Fyodor Kupolovda993802016-09-21 14:47:10 -0700318 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700319
Fyodor Kupolov945c97e2017-06-21 17:45:19 -0700320 IntentFilter userFilter = new IntentFilter();
321 userFilter.addAction(Intent.ACTION_USER_REMOVED);
322 mContext.registerReceiverAsUser(new BroadcastReceiver() {
323 @Override
324 public void onReceive(Context context, Intent intent) {
325 String action = intent.getAction();
326 if (Intent.ACTION_USER_REMOVED.equals(action)) {
327 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
328 if (userId < 1) return;
329 Slog.i(TAG, "User " + userId + " removed");
330 purgeUserData(userId);
331 }
332 }
333 }, UserHandle.ALL, userFilter, null, null);
334
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700335 // Need to cancel account request notifications if the update/install can access the account
336 new PackageMonitor() {
337 @Override
338 public void onPackageAdded(String packageName, int uid) {
339 // Called on a handler, and running as the system
340 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
341 }
342
343 @Override
344 public void onPackageUpdateFinished(String packageName, int uid) {
345 // Called on a handler, and running as the system
346 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
347 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700348 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700349
350 // Cancel account request notification if an app op was preventing the account access
351 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
352 new AppOpsManager.OnOpChangedInternalListener() {
353 @Override
354 public void onOpChanged(int op, String packageName) {
355 try {
356 final int userId = ActivityManager.getCurrentUser();
357 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
358 final int mode = mAppOpsManager.checkOpNoThrow(
359 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
360 if (mode == AppOpsManager.MODE_ALLOWED) {
361 final long identity = Binder.clearCallingIdentity();
362 try {
363 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
364 } finally {
365 Binder.restoreCallingIdentity(identity);
366 }
367 }
368 } catch (NameNotFoundException e) {
369 /* ignore */
370 }
371 }
372 });
373
374 // Cancel account request notification if a permission was preventing the account access
375 mPackageManager.addOnPermissionsChangeListener(
376 (int uid) -> {
377 Account[] accounts = null;
378 String[] packageNames = mPackageManager.getPackagesForUid(uid);
379 if (packageNames != null) {
380 final int userId = UserHandle.getUserId(uid);
381 final long identity = Binder.clearCallingIdentity();
382 try {
383 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800384 // if app asked for permission we need to cancel notification even
385 // for O+ applications.
386 if (mPackageManager.checkPermission(
387 Manifest.permission.GET_ACCOUNTS,
388 packageName) != PackageManager.PERMISSION_GRANTED) {
389 continue;
390 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700391
392 if (accounts == null) {
393 accounts = getAccountsAsUser(null, userId, "android");
394 if (ArrayUtils.isEmpty(accounts)) {
395 return;
396 }
397 }
398
399 for (Account account : accounts) {
400 cancelAccountAccessRequestNotificationIfNeeded(
401 account, uid, packageName, true);
402 }
403 }
404 } finally {
405 Binder.restoreCallingIdentity(identity);
406 }
407 }
408 });
409 }
410
411 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
412 boolean checkAccess) {
413 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
414 for (Account account : accounts) {
415 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
416 }
417 }
418
419 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
420 boolean checkAccess) {
421 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
422 for (Account account : accounts) {
423 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
424 }
425 }
426
427 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
428 boolean checkAccess) {
429 String[] packageNames = mPackageManager.getPackagesForUid(uid);
430 if (packageNames != null) {
431 for (String packageName : packageNames) {
432 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
433 packageName, checkAccess);
434 }
435 }
436 }
437
438 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
439 int uid, String packageName, boolean checkAccess) {
440 if (!checkAccess || hasAccountAccess(account, packageName,
441 UserHandle.getUserHandleForUid(uid))) {
442 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700443 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700444 UserHandle.getUserHandleForUid(uid));
445 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800446 }
447
Dianne Hackborn164371f2013-10-01 19:10:13 -0700448 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800449 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800450 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800451 Bundle.setDefusable(extras, true);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700452 int callingUid = Binder.getCallingUid();
453 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800454 if (Log.isLoggable(TAG, Log.VERBOSE)) {
455 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
456 + ", pid " + Binder.getCallingPid());
457 }
458 Preconditions.checkNotNull(account, "account cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800459 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
460 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
461 callingUid, account.type);
462 throw new SecurityException(msg);
463 }
464 /*
465 * Child users are not allowed to add accounts. Only the accounts that are shared by the
466 * parent profile can be added to child profile.
467 *
468 * TODO: Only allow accounts that were shared to be added by a limited user.
469 */
470 // fails if the account already exists
471 long identityToken = clearCallingIdentity();
472 try {
473 UserAccounts accounts = getUserAccounts(userId);
474 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800475 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800476 } finally {
477 restoreCallingIdentity(identityToken);
478 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700479 }
480
481 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800482 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
483 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800484 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700485 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800486 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700487 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800488
489 if ((accountType != null && !managedTypes.contains(accountType))
490 || (accountType == null && !isSystemUid)) {
491 throw new SecurityException(
492 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
493 + callingUid + " with packageName=" + packageName);
494 }
495 if (accountType != null) {
496 managedTypes = new ArrayList<String>();
497 managedTypes.add(accountType);
498 }
499
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800500 long identityToken = clearCallingIdentity();
501 try {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700502 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800503 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700504 accounts);
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800505 } finally {
506 restoreCallingIdentity(identityToken);
507 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800508 }
509
510 /*
511 * accountTypes may not be null
512 */
513 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
514 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700515 if (!packageExistsForUser(packageName, accounts.userId)) {
516 Log.d(TAG, "Package not found " + packageName);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800517 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800518 }
519
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800520 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800521 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700522 synchronized (accounts.dbLock) {
523 synchronized (accounts.cacheLock) {
524 final Account[] accountsOfType = accounts.accountCache.get(accountType);
525 if (accountsOfType != null) {
526 for (Account account : accountsOfType) {
527 result.put(account,
528 resolveAccountVisibility(account, packageName, accounts));
529 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800530 }
531 }
532 }
533 }
534 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800535 }
536
537 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800538 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700539 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700540 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700541 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800542 if (!isAccountManagedByCaller(account.type, callingUid, userId)
543 && !isSystemUid(callingUid)) {
544 String msg =
545 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700546 throw new SecurityException(msg);
547 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700548
549 long identityToken = clearCallingIdentity();
550 try {
551 UserAccounts accounts = getUserAccounts(userId);
552 synchronized (accounts.dbLock) {
553 synchronized (accounts.cacheLock) {
554 return getPackagesAndVisibilityForAccountLocked(account, accounts);
555 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700556 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700557 } finally {
558 restoreCallingIdentity(identityToken);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700559 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700560
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800561 }
562
563 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700564 * Returns Map with all package names and visibility values for given account.
565 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800566 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800567 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800568 * @param accounts UserAccount that currently hosts the account and application
569 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700570 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800571 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700572 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800573 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700574 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
575 if (accountVisibility == null) {
576 Log.d(TAG, "Visibility was not initialized");
577 accountVisibility = new HashMap<>();
578 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800579 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700580 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700581 }
582
583 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700584 public int getAccountVisibility(Account account, String packageName) {
585 Preconditions.checkNotNull(account, "account cannot be null");
586 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800587 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700588 int userId = UserHandle.getCallingUserId();
589 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800590 && !isSystemUid(callingUid)) {
591 String msg = String.format(
592 "uid %s cannot get secrets for accounts of type: %s",
593 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700594 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800595 throw new SecurityException(msg);
596 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700597 long identityToken = clearCallingIdentity();
598 try {
599 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyevcbe1bd12017-04-25 17:02:47 -0700600 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
601 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
602 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
603 return visibility;
604 } else {
605 return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
606 }
607 }
608 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_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_NOT_VISIBLE;
614 }
615 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700616 return resolveAccountVisibility(account, packageName, accounts);
617 } finally {
618 restoreCallingIdentity(identityToken);
619 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800620 }
621
622 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800623 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800624 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800625 * @param account The account to check visibility.
626 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800627 * @param accounts UserAccount that currently hosts the account and application
628 *
629 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
630 *
631 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700632 private int getAccountVisibilityFromCache(Account account, String packageName,
633 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700634 synchronized (accounts.cacheLock) {
635 Map<String, Integer> accountVisibility =
636 getPackagesAndVisibilityForAccountLocked(account, accounts);
637 Integer visibility = accountVisibility.get(packageName);
638 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800639 }
640 }
641
642 /**
643 * Method which handles default values for Account visibility.
644 *
645 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800646 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800647 * @param accounts UserAccount that currently hosts the account and application
648 *
649 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
650 *
651 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800652 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800653 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800654 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800655 int uid = -1;
656 try {
657 long identityToken = clearCallingIdentity();
658 try {
659 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
660 } finally {
661 restoreCallingIdentity(identityToken);
662 }
663 } catch (NameNotFoundException e) {
664 Log.d(TAG, "Package not found " + e.getMessage());
665 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800666 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800667
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800668 // System visibility can not be restricted.
669 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
670 return AccountManager.VISIBILITY_VISIBLE;
671 }
672
673 int signatureCheckResult =
674 checkPackageSignature(account.type, uid, accounts.userId);
675
676 // Authenticator can not restrict visibility to itself.
677 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
678 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
679 }
680
681 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700682 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800683
684 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
685 return visibility;
686 }
687
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700688 boolean isPrivileged = isPermittedForPackage(packageName, uid, accounts.userId,
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800689 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
690
691 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800692 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800693 return AccountManager.VISIBILITY_VISIBLE;
694 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800695
696 boolean preO = isPreOApplication(packageName);
697 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
Dmitry Dementyevd6f06722017-04-05 12:43:26 -0700698 || (preO && checkGetAccountsPermission(packageName, uid, accounts.userId))
699 || (checkReadContactsPermission(packageName, uid, accounts.userId)
700 && accountTypeManagesContacts(account.type, accounts.userId))
701 || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800702 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
703 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700704 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800705 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800706 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
707 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
708 }
709 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700710 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800711 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800712 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
713 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
714 }
715 }
716 return visibility;
717 }
718
719 /**
720 * Checks targetSdk for a package;
721 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800722 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800723 *
724 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
725 * undefined
726 */
727 private boolean isPreOApplication(String packageName) {
728 try {
729 long identityToken = clearCallingIdentity();
730 ApplicationInfo applicationInfo;
731 try {
732 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
733 } finally {
734 restoreCallingIdentity(identityToken);
735 }
736
737 if (applicationInfo != null) {
738 int version = applicationInfo.targetSdkVersion;
739 return version < android.os.Build.VERSION_CODES.O;
740 }
741 return true;
742 } catch (NameNotFoundException e) {
743 Log.d(TAG, "Package not found " + e.getMessage());
744 return true;
745 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800746 }
747
748 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700749 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
750 Preconditions.checkNotNull(account, "account cannot be null");
751 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800752 int callingUid = Binder.getCallingUid();
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700753 int userId = UserHandle.getCallingUserId();
754 if (!isAccountManagedByCaller(account.type, callingUid, userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800755 && !isSystemUid(callingUid)) {
756 String msg = String.format(
757 "uid %s cannot get secrets for accounts of type: %s",
758 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700759 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800760 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700761 }
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700762 long identityToken = clearCallingIdentity();
763 try {
764 UserAccounts accounts = getUserAccounts(userId);
765 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700766 accounts);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700767 } finally {
768 restoreCallingIdentity(identityToken);
769 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700770 }
771
sunjian066aa5e2017-06-05 12:16:59 -0700772 private boolean isVisible(int visibility) {
773 return visibility == AccountManager.VISIBILITY_VISIBLE ||
774 visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
775 }
776
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700777 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800778 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700779 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800780 * @param account Account to update visibility.
781 * @param packageName Package name for which visibility is updated.
782 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800783 * @param notify if the flag is set applications will get notification about visibility change
784 * @param accounts UserAccount that currently hosts the account and application
785 *
786 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700787 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800788 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800789 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700790 synchronized (accounts.dbLock) {
791 synchronized (accounts.cacheLock) {
792 Map<String, Integer> packagesToVisibility;
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700793 List<String> accountRemovedReceivers;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700794 if (notify) {
795 if (isSpecialPackageKey(packageName)) {
796 packagesToVisibility =
797 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700798 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700799 } else {
800 if (!packageExistsForUser(packageName, accounts.userId)) {
801 return false; // package is not installed.
802 }
803 packagesToVisibility = new HashMap<>();
804 packagesToVisibility.put(packageName,
805 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700806 accountRemovedReceivers = new ArrayList<>();
807 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
808 accountRemovedReceivers.add(packageName);
809 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700810 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800811 } else {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700812 // Notifications will not be send - only used during add account.
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700813 if (!isSpecialPackageKey(packageName) &&
814 !packageExistsForUser(packageName, accounts.userId)) {
815 // package is not installed and not meta value.
816 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100817 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700818 packagesToVisibility = Collections.emptyMap();
819 accountRemovedReceivers = Collections.emptyList();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800820 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700821
822 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800823 return false;
824 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800825
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700826 if (notify) {
827 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
828 .entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -0700829 int oldVisibility = packageToVisibility.getValue();
830 int currentVisibility =
831 resolveAccountVisibility(account, packageName, accounts);
832 if (isVisible(oldVisibility) != isVisible(currentVisibility)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700833 notifyPackage(packageToVisibility.getKey(), accounts);
834 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700835 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700836 for (String packageNameToNotify : accountRemovedReceivers) {
837 sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
838 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700839 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700840 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700841 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800842 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700843 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700844 }
845
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700846 // Update account visibility in cache and database.
847 private boolean updateAccountVisibilityLocked(Account account, String packageName,
848 int newVisibility, UserAccounts accounts) {
849 final long accountId = accounts.accountsDb.findDeAccountId(account);
850 if (accountId < 0) {
851 return false;
852 }
853
854 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
855 try {
856 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
857 newVisibility)) {
858 return false;
859 }
860 } finally {
861 StrictMode.setThreadPolicy(oldPolicy);
862 }
863 Map<String, Integer> accountVisibility =
864 getPackagesAndVisibilityForAccountLocked(account, accounts);
865 accountVisibility.put(packageName, newVisibility);
866 return true;
867 }
868
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700869 @Override
870 public void registerAccountListener(String[] accountTypes, String opPackageName) {
871 int callingUid = Binder.getCallingUid();
872 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700873
874 int userId = UserHandle.getCallingUserId();
875 long identityToken = clearCallingIdentity();
876 try {
877 UserAccounts accounts = getUserAccounts(userId);
878 registerAccountListener(accountTypes, opPackageName, accounts);
879 } finally {
880 restoreCallingIdentity(identityToken);
881 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800882 }
883
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700884 private void registerAccountListener(String[] accountTypes, String opPackageName,
885 UserAccounts accounts) {
886 synchronized (accounts.mReceiversForType) {
887 if (accountTypes == null) {
888 // null for any type
889 accountTypes = new String[] {null};
890 }
891 for (String type : accountTypes) {
892 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
893 if (receivers == null) {
894 receivers = new HashMap<>();
895 accounts.mReceiversForType.put(type, receivers);
896 }
897 Integer cnt = receivers.get(opPackageName);
898 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800899 }
900 }
901 }
902
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700903 @Override
904 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
905 int callingUid = Binder.getCallingUid();
906 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -0700907 int userId = UserHandle.getCallingUserId();
908 long identityToken = clearCallingIdentity();
909 try {
910 UserAccounts accounts = getUserAccounts(userId);
911 unregisterAccountListener(accountTypes, opPackageName, accounts);
912 } finally {
913 restoreCallingIdentity(identityToken);
914 }
915 }
916
917 private void unregisterAccountListener(String[] accountTypes, String opPackageName,
918 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700919 synchronized (accounts.mReceiversForType) {
920 if (accountTypes == null) {
921 // null for any type
922 accountTypes = new String[] {null};
923 }
924 for (String type : accountTypes) {
925 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
926 if (receivers == null || receivers.get(opPackageName) == null) {
927 throw new IllegalArgumentException("attempt to unregister wrong receiver");
928 }
929 Integer cnt = receivers.get(opPackageName);
930 if (cnt == 1) {
931 receivers.remove(opPackageName);
932 } else {
933 receivers.put(opPackageName, cnt - 1);
934 }
935 }
936 }
937 }
938
939 // Send notification to all packages which can potentially see the account
940 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
941 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700942
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700943 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700944 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
945 && (packageToVisibility.getValue()
946 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700947 notifyPackage(packageToVisibility.getKey(), accounts);
948 }
949 }
950 }
951
952 /**
953 * Sends a direct intent to a package, notifying it of account visibility change.
954 *
955 * @param packageName to send Account to
956 * @param accounts UserAccount that currently hosts the account
957 */
958 private void notifyPackage(String packageName, UserAccounts accounts) {
959 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
960 intent.setPackage(packageName);
961 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
962 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
963 }
964
965 // Returns a map from package name to visibility, for packages subscribed
966 // to notifications about any account type, or type of provided account
967 // account type or all types.
968 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
969 Set<String> packages = new HashSet<>();
970 synchronized (accounts.mReceiversForType) {
971 for (String type : new String[] {account.type, null}) {
972 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
973 if (receivers != null) {
974 packages.addAll(receivers.keySet());
975 }
976 }
977 }
978 Map<String, Integer> result = new HashMap<>();
979 for (String packageName : packages) {
980 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
981 }
982 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800983 }
984
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -0700985 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
986 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
987 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
988 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
989 List<ResolveInfo> receivers =
990 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
991 List<String> result = new ArrayList<>();
992 if (receivers == null) {
993 return result;
994 }
995 for (ResolveInfo resolveInfo: receivers) {
996 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
997 int visibility = resolveAccountVisibility(account, packageName, accounts);
998 if (visibility == AccountManager.VISIBILITY_VISIBLE
999 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1000 result.add(packageName);
1001 }
1002 }
1003 return result;
1004 }
1005
1006 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
1007 private boolean shouldNotifyPackageOnAccountRemoval(Account account,
1008 String packageName, UserAccounts accounts) {
1009 int visibility = resolveAccountVisibility(account, packageName, accounts);
1010 if (visibility != AccountManager.VISIBILITY_VISIBLE
1011 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
1012 return false;
1013 }
1014
1015 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1016 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1017 intent.setPackage(packageName);
1018 List<ResolveInfo> receivers =
1019 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
1020 return (receivers != null && receivers.size() > 0);
1021 }
1022
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001023 private boolean packageExistsForUser(String packageName, int userId) {
1024 try {
1025 long identityToken = clearCallingIdentity();
1026 try {
1027 mPackageManager.getPackageUidAsUser(packageName, userId);
Dmitry Dementyev5c80deb2017-04-04 11:12:42 -07001028 return true;
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001029 } finally {
1030 restoreCallingIdentity(identityToken);
1031 }
1032 } catch (NameNotFoundException e) {
1033 return false;
1034 }
1035 }
1036
1037 /**
1038 * Returns true if packageName is one of special values.
1039 */
1040 private boolean isSpecialPackageKey(String packageName) {
1041 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
1042 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
1043 }
1044
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001045 private void sendAccountsChangedBroadcast(int userId) {
1046 Log.i(TAG, "the accounts changed, sending broadcast of "
1047 + ACCOUNTS_CHANGED_INTENT.getAction());
1048 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001049 }
1050
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001051 private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001052 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
1053 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001054 intent.setPackage(packageName);
1055 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
1056 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Dmitry Dementyeva461e302017-04-12 11:00:48 -07001057 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
1058 }
1059
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001060 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -07001061 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1062 throws RemoteException {
1063 try {
1064 return super.onTransact(code, data, reply, flags);
1065 } catch (RuntimeException e) {
1066 // The account manager only throws security exceptions, so let's
1067 // log all others.
1068 if (!(e instanceof SecurityException)) {
1069 Slog.wtf(TAG, "Account Manager Crash", e);
1070 }
1071 throw e;
1072 }
1073 }
1074
Amith Yamasani258848d2012-08-10 17:06:33 -07001075 private UserManager getUserManager() {
1076 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -07001077 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -07001078 }
1079 return mUserManager;
1080 }
1081
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001082 /**
1083 * Validate internal set of accounts against installed authenticators for
1084 * given user. Clears cached authenticators before validating.
1085 */
1086 public void validateAccounts(int userId) {
1087 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001088 // Invalidate user-specific cache to make sure we catch any
1089 // removed authenticators.
1090 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
1091 }
1092
1093 /**
1094 * Validate internal set of accounts against installed authenticators for
1095 * given user. Clear cached authenticators before validating when requested.
1096 */
1097 private void validateAccountsInternal(
1098 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001099 if (Log.isLoggable(TAG, Log.DEBUG)) {
1100 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001101 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001102 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001103 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001104
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001105 if (invalidateAuthenticatorCache) {
1106 mAuthenticatorCache.invalidateCache(accounts.userId);
1107 }
1108
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001109 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
1110 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001111 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001112
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001113 synchronized (accounts.dbLock) {
1114 synchronized (accounts.cacheLock) {
1115 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001116
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001117 // Get a map of stored authenticator types to UID
1118 final AccountsDb accountsDb = accounts.accountsDb;
1119 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
1120 // Create a list of authenticator type whose previous uid no longer exists
1121 HashSet<String> obsoleteAuthType = Sets.newHashSet();
1122 SparseBooleanArray knownUids = null;
1123 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
1124 String type = authToUidEntry.getKey();
1125 int uid = authToUidEntry.getValue();
1126 Integer knownUid = knownAuth.get(type);
1127 if (knownUid != null && uid == knownUid) {
1128 // Remove it from the knownAuth list if it's unchanged.
1129 knownAuth.remove(type);
1130 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001131 /*
1132 * The authenticator is presently not cached and should only be triggered
1133 * when we think an authenticator has been removed (or is being updated).
1134 * But we still want to check if any data with the associated uid is
1135 * around. This is an (imperfect) signal that the package may be updating.
1136 *
1137 * A side effect of this is that an authenticator sharing a uid with
1138 * multiple apps won't get its credentials wiped as long as some app with
1139 * that uid is still on the device. But I suspect that this is a rare case.
1140 * And it isn't clear to me how an attacker could really exploit that
1141 * feature.
1142 *
1143 * The upshot is that we don't have to worry about accounts getting
1144 * uninstalled while the authenticator's package is being updated.
1145 *
1146 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001147 if (knownUids == null) {
1148 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1149 }
1150 if (!knownUids.get(uid)) {
1151 // The authenticator is not presently available to the cache. And the
1152 // package no longer has a data directory (so we surmise it isn't
1153 // updating). So purge its data from the account databases.
1154 obsoleteAuthType.add(type);
1155 // And delete it from the TABLE_META
1156 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1157 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001158 }
1159 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001160
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001161 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1162 // been re-enabled (after being updated for example), then we just overwrite the old
1163 // values.
1164 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1165 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1166 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001167
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001168 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1169 try {
1170 accounts.accountCache.clear();
1171 final HashMap<String, ArrayList<String>> accountNamesByType
1172 = new LinkedHashMap<>();
1173 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1174 final long accountId = accountEntry.getKey();
1175 final Account account = accountEntry.getValue();
1176 if (obsoleteAuthType.contains(account.type)) {
1177 Slog.w(TAG, "deleting account " + account.name + " because type "
1178 + account.type
1179 + "'s registered authenticator no longer exist.");
1180 Map<String, Integer> packagesToVisibility =
1181 getRequestingPackages(account, accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001182 List<String> accountRemovedReceivers =
1183 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001184 accountsDb.beginTransaction();
1185 try {
1186 accountsDb.deleteDeAccount(accountId);
1187 // Also delete from CE table if user is unlocked; if user is
1188 // currently locked the account will be removed later by
1189 // syncDeCeAccountsLocked
1190 if (userUnlocked) {
1191 accountsDb.deleteCeAccount(accountId);
1192 }
1193 accountsDb.setTransactionSuccessful();
1194 } finally {
1195 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001196 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001197 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001198
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001199 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1200 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001201
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001202 accounts.userDataCache.remove(account);
1203 accounts.authTokenCache.remove(account);
1204 accounts.accountTokenCaches.remove(account);
1205 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001206
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001207 for (Entry<String, Integer> packageToVisibility :
1208 packagesToVisibility.entrySet()) {
sunjian066aa5e2017-06-05 12:16:59 -07001209 if (isVisible(packageToVisibility.getValue())) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001210 notifyPackage(packageToVisibility.getKey(), accounts);
1211 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001212 }
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07001213 for (String packageName : accountRemovedReceivers) {
1214 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
1215 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001216 } else {
1217 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1218 if (accountNames == null) {
1219 accountNames = new ArrayList<>();
1220 accountNamesByType.put(account.type, accountNames);
1221 }
1222 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001223 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001224 }
1225 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1226 final String accountType = cur.getKey();
1227 final ArrayList<String> accountNames = cur.getValue();
1228 final Account[] accountsForType = new Account[accountNames.size()];
1229 for (int i = 0; i < accountsForType.length; i++) {
1230 accountsForType[i] = new Account(accountNames.get(i), accountType,
1231 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001232 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001233 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001234 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001235 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1236 } finally {
1237 if (accountDeleted) {
1238 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001239 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001240 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001241 }
1242 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001243 }
1244
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001245 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1246 // Get the UIDs of all apps that might have data on the device. We want
1247 // to preserve user data if the app might otherwise be storing data.
1248 List<PackageInfo> pkgsWithData =
1249 mPackageManager.getInstalledPackagesAsUser(
1250 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1251 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1252 for (PackageInfo pkgInfo : pkgsWithData) {
1253 if (pkgInfo.applicationInfo != null
1254 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1255 knownUids.put(pkgInfo.applicationInfo.uid, true);
1256 }
1257 }
1258 return knownUids;
1259 }
1260
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001261 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001262 Context context,
1263 int userId) {
1264 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001265 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1266 }
1267
1268 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1269 IAccountAuthenticatorCache authCache,
1270 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001271 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001272 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1273 .getAllServices(userId)) {
1274 knownAuth.put(service.type.type, service.uid);
1275 }
1276 return knownAuth;
1277 }
1278
Amith Yamasani04e0d262012-02-14 11:50:53 -08001279 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001280 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001281 }
1282
1283 protected UserAccounts getUserAccounts(int userId) {
1284 synchronized (mUsers) {
1285 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001286 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001287 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001288 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1289 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001290 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001291 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001292 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001293 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001294 validateAccounts = true;
1295 }
1296 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001297 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001298 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001299 synchronized (accounts.dbLock) {
1300 synchronized (accounts.cacheLock) {
1301 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1302 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1303 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001304 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001305 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001306 }
1307 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001308 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001309 }
1310 return accounts;
1311 }
1312 }
1313
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001314 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1315 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001316 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001317 if (!accountsToRemove.isEmpty()) {
1318 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1319 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001320 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1321 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001322
1323 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001324 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001325 }
1326 }
1327 }
1328
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001329 private void purgeOldGrantsAll() {
1330 synchronized (mUsers) {
1331 for (int i = 0; i < mUsers.size(); i++) {
1332 purgeOldGrants(mUsers.valueAt(i));
1333 }
1334 }
1335 }
1336
1337 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001338 synchronized (accounts.dbLock) {
1339 synchronized (accounts.cacheLock) {
1340 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1341 for (int uid : uids) {
1342 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1343 if (packageExists) {
1344 continue;
1345 }
1346 Log.d(TAG, "deleting grants for UID " + uid
1347 + " because its package is no longer installed");
1348 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001349 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001350 }
1351 }
1352 }
1353
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001354 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001355 if (isSpecialPackageKey(packageName)) {
1356 return;
1357 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001358 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001359 int numberOfUsers = mUsers.size();
1360 for (int i = 0; i < numberOfUsers; i++) {
1361 UserAccounts accounts = mUsers.valueAt(i);
1362 try {
1363 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1364 } catch (NameNotFoundException e) {
1365 // package does not exist - remove visibility values
1366 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001367 synchronized (accounts.dbLock) {
1368 synchronized (accounts.cacheLock) {
1369 for (Account account : accounts.visibilityCache.keySet()) {
1370 Map<String, Integer> accountVisibility =
1371 getPackagesAndVisibilityForAccountLocked(account, accounts);
1372 accountVisibility.remove(packageName);
1373 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001374 }
1375 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001376 }
1377 }
1378 }
1379 }
1380
Fyodor Kupolov945c97e2017-06-21 17:45:19 -07001381 private void purgeUserData(int userId) {
Amith Yamasani13593602012-03-22 16:16:17 -07001382 UserAccounts accounts;
1383 synchronized (mUsers) {
1384 accounts = mUsers.get(userId);
1385 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001386 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001387 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001388 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001389 synchronized (accounts.dbLock) {
1390 synchronized (accounts.cacheLock) {
Fyodor Kupolov56e158f2017-05-23 16:41:51 -07001391 accounts.statementForLogging.close();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001392 accounts.accountsDb.close();
1393 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001394 }
Amith Yamasani13593602012-03-22 16:16:17 -07001395 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001396 }
1397
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001398 @VisibleForTesting
1399 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001400 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1401 }
1402
1403 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001404 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1405 Log.v(TAG, "onUserUnlocked " + userId);
1406 }
1407 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001408 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001409 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001410 if (userId < 1) return;
Fyodor Kupolov2bc895d2017-12-19 11:53:47 -08001411 mHandler.post(() -> syncSharedAccounts(userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001412 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001413
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001414 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001415 // Check if there's a shared account that needs to be created as an account
1416 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1417 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001418 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001419 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001420 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001421 : UserHandle.USER_SYSTEM;
1422 if (parentUserId < 0) {
1423 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1424 return;
1425 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001426 for (Account sa : sharedAccounts) {
1427 if (ArrayUtils.contains(accounts, sa)) continue;
1428 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001429 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001430 }
1431 }
1432
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001433 @Override
1434 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001435 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001436 }
1437
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001438 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001439 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001440 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001441 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1442 Log.v(TAG, "getPassword: " + account
1443 + ", caller's uid " + Binder.getCallingUid()
1444 + ", pid " + Binder.getCallingPid());
1445 }
Fred Quintana382601f2010-03-25 12:25:10 -07001446 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001447 int userId = UserHandle.getCallingUserId();
1448 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001449 String msg = String.format(
1450 "uid %s cannot get secrets for accounts of type: %s",
1451 callingUid,
1452 account.type);
1453 throw new SecurityException(msg);
1454 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001455 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001456 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001457 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001458 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001459 } finally {
1460 restoreCallingIdentity(identityToken);
1461 }
1462 }
1463
Amith Yamasani04e0d262012-02-14 11:50:53 -08001464 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001465 if (account == null) {
1466 return null;
1467 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001468 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001469 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1470 return null;
1471 }
Fred Quintana31957f12009-10-21 13:43:10 -07001472
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001473 synchronized (accounts.dbLock) {
1474 synchronized (accounts.cacheLock) {
1475 return accounts.accountsDb
1476 .findAccountPasswordByNameAndType(account.name, account.type);
1477 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001478 }
1479 }
1480
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001481 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001482 public String getPreviousName(Account account) {
1483 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1484 Log.v(TAG, "getPreviousName: " + account
1485 + ", caller's uid " + Binder.getCallingUid()
1486 + ", pid " + Binder.getCallingPid());
1487 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001488 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001489 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001490 long identityToken = clearCallingIdentity();
1491 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001492 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001493 return readPreviousNameInternal(accounts, account);
1494 } finally {
1495 restoreCallingIdentity(identityToken);
1496 }
1497 }
1498
1499 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1500 if (account == null) {
1501 return null;
1502 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001503 synchronized (accounts.dbLock) {
1504 synchronized (accounts.cacheLock) {
1505 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1506 if (previousNameRef == null) {
1507 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1508 previousNameRef = new AtomicReference<>(previousName);
1509 accounts.previousNameCache.put(account, previousNameRef);
1510 return previousName;
1511 } else {
1512 return previousNameRef.get();
1513 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001514 }
1515 }
1516 }
1517
1518 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001519 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001520 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001521 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001522 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1523 account, key, callingUid, Binder.getCallingPid());
1524 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001525 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001526 Preconditions.checkNotNull(account, "account cannot be null");
1527 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001528 int userId = UserHandle.getCallingUserId();
1529 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001530 String msg = String.format(
1531 "uid %s cannot get user data for accounts of type: %s",
1532 callingUid,
1533 account.type);
1534 throw new SecurityException(msg);
1535 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001536 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001537 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1538 return null;
1539 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001540 long identityToken = clearCallingIdentity();
1541 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001542 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001543 if (!accountExistsCache(accounts, account)) {
1544 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001545 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001546 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001547 } finally {
1548 restoreCallingIdentity(identityToken);
1549 }
1550 }
1551
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001552 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001553 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001554 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001555 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1556 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001557 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001558 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001559 + ", pid " + Binder.getCallingPid());
1560 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001561 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001562 if (isCrossUser(callingUid, userId)) {
1563 throw new SecurityException(
1564 String.format(
1565 "User %s tying to get authenticator types for %s" ,
1566 UserHandle.getCallingUserId(),
1567 userId));
1568 }
1569
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001570 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001571 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001572 return getAuthenticatorTypesInternal(userId);
1573
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001574 } finally {
1575 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001576 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001577 }
1578
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001579 /**
1580 * Should only be called inside of a clearCallingIdentity block.
1581 */
1582 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001583 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001584 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1585 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1586 AuthenticatorDescription[] types =
1587 new AuthenticatorDescription[authenticatorCollection.size()];
1588 int i = 0;
1589 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1590 : authenticatorCollection) {
1591 types[i] = authenticator.type;
1592 i++;
1593 }
1594 return types;
1595 }
1596
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001597 private boolean isCrossUser(int callingUid, int userId) {
1598 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001599 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001600 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001601 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1602 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001603 }
1604
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001605 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001606 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001607 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001608 }
1609
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001610 @Override
1611 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001612 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001613 int callingUid = Binder.getCallingUid();
1614 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1615 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001616 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001617 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001618 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1619 final UserAccounts toAccounts = getUserAccounts(userTo);
1620 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001621 if (response != null) {
1622 Bundle result = new Bundle();
1623 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1624 try {
1625 response.onResult(result);
1626 } catch (RemoteException e) {
1627 Slog.w(TAG, "Failed to report error back to the client." + e);
1628 }
1629 }
1630 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001631 }
1632
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001633 Slog.d(TAG, "Copying account " + account.name
1634 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001635 long identityToken = clearCallingIdentity();
1636 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001637 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001638 false /* stripAuthTokenFromResult */, account.name,
1639 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001640 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001641 protected String toDebugString(long now) {
1642 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1643 + ", " + account.type;
1644 }
1645
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001646 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001647 public void run() throws RemoteException {
1648 mAuthenticator.getAccountCredentialsForCloning(this, account);
1649 }
1650
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001651 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001652 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001653 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001654 if (result != null
1655 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1656 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001657 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001658 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001659 super.onResult(result);
1660 }
1661 }
1662 }.bind();
1663 } finally {
1664 restoreCallingIdentity(identityToken);
1665 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001666 }
1667
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001668 @Override
1669 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001670 final int callingUid = Binder.getCallingUid();
1671 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1672 String msg = String.format(
1673 "accountAuthenticated( account: %s, callerUid: %s)",
1674 account,
1675 callingUid);
1676 Log.v(TAG, msg);
1677 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001678 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001679 int userId = UserHandle.getCallingUserId();
1680 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001681 String msg = String.format(
1682 "uid %s cannot notify authentication for accounts of type: %s",
1683 callingUid,
1684 account.type);
1685 throw new SecurityException(msg);
1686 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001687
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001688 if (!canUserModifyAccounts(userId, callingUid) ||
1689 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001690 return false;
1691 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001692
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001693 long identityToken = clearCallingIdentity();
1694 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001695 UserAccounts accounts = getUserAccounts(userId);
1696 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001697 } finally {
1698 restoreCallingIdentity(identityToken);
1699 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001700 }
1701
1702 private boolean updateLastAuthenticatedTime(Account account) {
1703 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001704 synchronized (accounts.dbLock) {
1705 synchronized (accounts.cacheLock) {
1706 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1707 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001708 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001709 }
1710
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001711 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001712 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1713 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001714 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001715 long id = clearCallingIdentity();
1716 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001717 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001718 false /* stripAuthTokenFromResult */, account.name,
1719 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001720 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001721 protected String toDebugString(long now) {
1722 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1723 + ", " + account.type;
1724 }
1725
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001726 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001727 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001728 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001729 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1730 if (acc.equals(account)) {
1731 mAuthenticator.addAccountFromCredentials(
1732 this, account, accountCredentials);
1733 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001734 }
1735 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001736 }
1737
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001738 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001739 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001740 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001741 // TODO: Anything to do if if succedded?
1742 // TODO: If it failed: Show error notification? Should we remove the shadow
1743 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001744 // TODO: what we do with the visibility?
1745
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001746 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001747 }
1748
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001749 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001750 public void onError(int errorCode, String errorMessage) {
1751 super.onError(errorCode, errorMessage);
1752 // TODO: Show error notification to user
1753 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1754 }
1755
1756 }.bind();
1757 } finally {
1758 restoreCallingIdentity(id);
1759 }
1760 }
1761
Amith Yamasani04e0d262012-02-14 11:50:53 -08001762 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001763 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001764 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001765 if (account == null) {
1766 return false;
1767 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001768 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001769 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1770 + " is locked. callingUid=" + callingUid);
1771 return false;
1772 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001773 synchronized (accounts.dbLock) {
1774 synchronized (accounts.cacheLock) {
1775 accounts.accountsDb.beginTransaction();
1776 try {
1777 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1778 Log.w(TAG, "insertAccountIntoDatabase: " + account
1779 + ", skipping since the account already exists");
1780 return false;
1781 }
1782 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1783 if (accountId < 0) {
1784 Log.w(TAG, "insertAccountIntoDatabase: " + account
1785 + ", skipping the DB insert failed");
1786 return false;
1787 }
1788 // Insert into DE table
1789 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1790 Log.w(TAG, "insertAccountIntoDatabase: " + account
1791 + ", skipping the DB insert failed");
1792 return false;
1793 }
1794 if (extras != null) {
1795 for (String key : extras.keySet()) {
1796 final String value = extras.getString(key);
1797 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1798 Log.w(TAG, "insertAccountIntoDatabase: " + account
1799 + ", skipping since insertExtra failed for key " + key);
1800 return false;
1801 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001802 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001803 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001804
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001805 if (packageToVisibility != null) {
1806 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1807 setAccountVisibility(account, entry.getKey() /* package */,
1808 entry.getValue() /* visibility */, false /* notify */,
1809 accounts);
1810 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001811 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001812 accounts.accountsDb.setTransactionSuccessful();
1813
1814 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1815 accountId,
1816 accounts, callingUid);
1817
1818 insertAccountIntoCacheLocked(accounts, account);
1819 } finally {
1820 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001821 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001822 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001823 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001824 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1825 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001826 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001827
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001828 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001829 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1830 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001831
Amith Yamasani5be347b2013-03-31 17:44:31 -07001832 return true;
1833 }
1834
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001835 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001836 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001837 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001838 }
1839 }
1840
Amith Yamasani5be347b2013-03-31 17:44:31 -07001841 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001842 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001843 * running, then clone the account too.
1844 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001845 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001846 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001847 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001848 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001849 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001850 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001851 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001852 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001853 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001854 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001855 }
1856 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001857 }
1858 }
1859
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001860 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001861 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001862 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001863 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001864 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001865 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1866 Log.v(TAG, "hasFeatures: " + account
1867 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001868 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001869 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001870 + ", pid " + Binder.getCallingPid());
1871 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001872 Preconditions.checkArgument(account != null, "account cannot be null");
1873 Preconditions.checkArgument(response != null, "response cannot be null");
1874 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001875 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001876 checkReadAccountsPermitted(callingUid, account.type, userId,
1877 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001878
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001879 long identityToken = clearCallingIdentity();
1880 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001881 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001882 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001883 } finally {
1884 restoreCallingIdentity(identityToken);
1885 }
1886 }
1887
1888 private class TestFeaturesSession extends Session {
1889 private final String[] mFeatures;
1890 private final Account mAccount;
1891
Amith Yamasani04e0d262012-02-14 11:50:53 -08001892 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001893 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001894 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001895 true /* stripAuthTokenFromResult */, account.name,
1896 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001897 mFeatures = features;
1898 mAccount = account;
1899 }
1900
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001901 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001902 public void run() throws RemoteException {
1903 try {
1904 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1905 } catch (RemoteException e) {
1906 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1907 }
1908 }
1909
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001910 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001911 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001912 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001913 IAccountManagerResponse response = getResponseAndClose();
1914 if (response != null) {
1915 try {
1916 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001917 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001918 return;
1919 }
Fred Quintana56285a62010-12-02 14:20:51 -08001920 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1921 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1922 + response);
1923 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001924 final Bundle newResult = new Bundle();
1925 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1926 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1927 response.onResult(newResult);
1928 } catch (RemoteException e) {
1929 // if the caller is dead then there is no one to care about remote exceptions
1930 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1931 Log.v(TAG, "failure while notifying response", e);
1932 }
1933 }
1934 }
1935 }
1936
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001937 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001938 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001939 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001940 + ", " + mAccount
1941 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1942 }
1943 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001944
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001945 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001946 public void renameAccount(
1947 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001948 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001949 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1950 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001951 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001952 + ", pid " + Binder.getCallingPid());
1953 }
1954 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001955 int userId = UserHandle.getCallingUserId();
1956 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001957 String msg = String.format(
1958 "uid %s cannot rename accounts of type: %s",
1959 callingUid,
1960 accountToRename.type);
1961 throw new SecurityException(msg);
1962 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001963 long identityToken = clearCallingIdentity();
1964 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001965 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001966 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001967 Bundle result = new Bundle();
1968 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1969 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001970 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1971 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001972 try {
1973 response.onResult(result);
1974 } catch (RemoteException e) {
1975 Log.w(TAG, e.getMessage());
1976 }
1977 } finally {
1978 restoreCallingIdentity(identityToken);
1979 }
1980 }
1981
1982 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001983 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001984 Account resultAccount = null;
1985 /*
1986 * Cancel existing notifications. Let authenticators
1987 * re-post notifications as required. But we don't know if
1988 * the authenticators have bound their notifications to
1989 * now stale account name data.
1990 *
1991 * With a rename api, we might not need to do this anymore but it
1992 * shouldn't hurt.
1993 */
1994 cancelNotification(
1995 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04001996 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001997 synchronized(accounts.credentialsPermissionNotificationIds) {
1998 for (Pair<Pair<Account, String>, Integer> pair:
1999 accounts.credentialsPermissionNotificationIds.keySet()) {
2000 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002001 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002002 cancelNotification(id, new UserHandle(accounts.userId));
2003 }
2004 }
2005 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002006 synchronized (accounts.dbLock) {
2007 synchronized (accounts.cacheLock) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002008 List<String> accountRemovedReceivers =
2009 getAccountRemovedReceivers(accountToRename, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002010 accounts.accountsDb.beginTransaction();
2011 Account renamedAccount = new Account(newName, accountToRename.type);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002012 try {
chengangf2d081c2017-12-27 17:17:32 +08002013 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
2014 Log.e(TAG, "renameAccount failed - account with new name already exists");
2015 return null;
2016 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002017 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
2018 if (accountId >= 0) {
2019 accounts.accountsDb.renameCeAccount(accountId, newName);
2020 if (accounts.accountsDb.renameDeAccount(
2021 accountId, newName, accountToRename.name)) {
2022 accounts.accountsDb.setTransactionSuccessful();
2023 } else {
2024 Log.e(TAG, "renameAccount failed");
2025 return null;
2026 }
2027 } else {
2028 Log.e(TAG, "renameAccount failed - old account does not exist");
2029 return null;
2030 }
2031 } finally {
2032 accounts.accountsDb.endTransaction();
2033 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002034 /*
2035 * Database transaction was successful. Clean up cached
2036 * data associated with the account in the user profile.
2037 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002038 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002039 /*
2040 * Extract the data and token caches before removing the
2041 * old account to preserve the user data associated with
2042 * the account.
2043 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002044 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
2045 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
2046 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
2047 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002048 /*
2049 * Update the cached data associated with the renamed
2050 * account.
2051 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002052 accounts.userDataCache.put(renamedAccount, tmpData);
2053 accounts.authTokenCache.put(renamedAccount, tmpTokens);
2054 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
2055 accounts.previousNameCache.put(
2056 renamedAccount,
2057 new AtomicReference<>(accountToRename.name));
2058 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002059
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002060 int parentUserId = accounts.userId;
2061 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002062 /*
2063 * Owner or system user account was renamed, rename the account for
2064 * those users with which the account was shared.
2065 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002066 List<UserInfo> users = getUserManager().getUsers(true);
2067 for (UserInfo user : users) {
2068 if (user.isRestricted()
2069 && (user.restrictedProfileParentId == parentUserId)) {
2070 renameSharedAccountAsUser(accountToRename, newName, user.id);
2071 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002072 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002073 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002074
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002075 sendNotificationAccountUpdated(resultAccount, accounts);
2076 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002077 for (String packageName : accountRemovedReceivers) {
2078 sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
2079 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002080 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002081 }
2082 return resultAccount;
2083 }
2084
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002085 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002086 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002087 return userInfo != null && userInfo.canHaveProfile();
2088 }
2089
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07002090 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002091 public void removeAccount(IAccountManagerResponse response, Account account,
2092 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002093 removeAccountAsUser(
2094 response,
2095 account,
2096 expectActivityLaunch,
2097 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002098 }
2099
2100 @Override
2101 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002102 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002103 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002104 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2105 Log.v(TAG, "removeAccount: " + account
2106 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002107 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002108 + ", pid " + Binder.getCallingPid()
2109 + ", for user id " + userId);
2110 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002111 Preconditions.checkArgument(account != null, "account cannot be null");
2112 Preconditions.checkArgument(response != null, "response cannot be null");
2113
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002114 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002115 if (isCrossUser(callingUid, userId)) {
2116 throw new SecurityException(
2117 String.format(
2118 "User %s tying remove account for %s" ,
2119 UserHandle.getCallingUserId(),
2120 userId));
2121 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002122 /*
Alex Chauf788f9c2017-12-08 15:16:46 +00002123 * Only the system, authenticator or profile owner should be allowed to remove accounts for
2124 * that authenticator. This will let users remove accounts (via Settings in the system) but
2125 * not arbitrary applications (like competing authenticators).
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002126 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002127 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00002128 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
Alex Chauf788f9c2017-12-08 15:16:46 +00002129 && !isSystemUid(callingUid)
2130 && !isProfileOwner(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002131 String msg = String.format(
2132 "uid %s cannot remove accounts of type: %s",
2133 callingUid,
2134 account.type);
2135 throw new SecurityException(msg);
2136 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002137 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002138 try {
2139 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2140 "User cannot modify accounts");
2141 } catch (RemoteException re) {
2142 }
2143 return;
2144 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002145 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002146 try {
2147 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2148 "User cannot modify accounts of this type (policy).");
2149 } catch (RemoteException re) {
2150 }
2151 return;
2152 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002153 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002154 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002155 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002156 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002157 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002158 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002159 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002160 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002161 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002162 }
2163 }
2164 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002165 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002166 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002167 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2168 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002169 accountId,
2170 accounts,
2171 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002172 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002173 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2174 } finally {
2175 restoreCallingIdentity(identityToken);
2176 }
2177 }
2178
2179 @Override
2180 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002181 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002182 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2183 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002184 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002185 + ", pid " + Binder.getCallingPid());
2186 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002187 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002188 if (account == null) {
2189 /*
2190 * Null accounts should result in returning false, as per
2191 * AccountManage.addAccountExplicitly(...) java doc.
2192 */
2193 Log.e(TAG, "account is null");
2194 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002195 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002196 String msg = String.format(
Brandon Weeks9e4e96d2017-08-24 15:24:16 -07002197 "uid %s cannot explicitly remove accounts of type: %s",
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002198 callingUid,
2199 account.type);
2200 throw new SecurityException(msg);
2201 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002202 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002203 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002204 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002205 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2206 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002207 accountId,
2208 accounts,
2209 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002210 long identityToken = clearCallingIdentity();
2211 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002212 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002213 } finally {
2214 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002215 }
Fred Quintana60307342009-03-24 22:48:12 -07002216 }
2217
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002218 private class RemoveAccountSession extends Session {
2219 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002220 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002221 Account account, boolean expectActivityLaunch) {
2222 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002223 true /* stripAuthTokenFromResult */, account.name,
2224 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002225 mAccount = account;
2226 }
2227
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002228 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002229 protected String toDebugString(long now) {
2230 return super.toDebugString(now) + ", removeAccount"
2231 + ", account " + mAccount;
2232 }
2233
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002234 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002235 public void run() throws RemoteException {
2236 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2237 }
2238
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002239 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002240 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002241 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002242 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2243 && !result.containsKey(AccountManager.KEY_INTENT)) {
2244 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002245 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002246 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002247 }
2248 IAccountManagerResponse response = getResponseAndClose();
2249 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002250 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2251 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2252 + response);
2253 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002254 try {
tiansiming5330b5a2017-10-13 10:57:25 +08002255 response.onResult(result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002256 } catch (RemoteException e) {
tiansiming5330b5a2017-10-13 10:57:25 +08002257 Slog.e(TAG, "Error calling onResult()", e);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002258 }
2259 }
2260 }
2261 super.onResult(result);
2262 }
2263 }
2264
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002265 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002266 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002267 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002268 }
2269
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002270 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002271 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002272 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002273 if (!userUnlocked) {
2274 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2275 + " is still locked. CE data will be removed later");
2276 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002277 synchronized (accounts.dbLock) {
2278 synchronized (accounts.cacheLock) {
2279 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2280 accounts);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002281 List<String> accountRemovedReceivers =
2282 getAccountRemovedReceivers(account, accounts);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002283 accounts.accountsDb.beginTransaction();
2284 // Set to a dummy value, this will only be used if the database
2285 // transaction succeeds.
2286 long accountId = -1;
2287 try {
2288 accountId = accounts.accountsDb.findDeAccountId(account);
2289 if (accountId >= 0) {
2290 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002291 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002292 // always delete from CE table if CE storage is available
2293 // DE account could be removed while CE was locked
2294 if (userUnlocked) {
2295 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2296 if (ceAccountId >= 0) {
2297 accounts.accountsDb.deleteCeAccount(ceAccountId);
2298 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002299 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002300 accounts.accountsDb.setTransactionSuccessful();
2301 } finally {
2302 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002303 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002304 if (isChanged) {
2305 removeAccountFromCacheLocked(accounts, account);
2306 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2307 .entrySet()) {
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002308 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
2309 || (packageToVisibility.getValue()
2310 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002311 notifyPackage(packageToVisibility.getKey(), accounts);
2312 }
2313 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002314
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002315 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2316 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyevb6a7dc02017-04-18 13:43:31 -07002317 for (String packageName : accountRemovedReceivers) {
2318 sendAccountRemovedBroadcast(account, packageName, accounts.userId);
2319 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002320 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2321 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2322 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2323 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002324 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002325 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002326 long id = Binder.clearCallingIdentity();
2327 try {
2328 int parentUserId = accounts.userId;
2329 if (canHaveProfile(parentUserId)) {
2330 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002331 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002332 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002333 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002334 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002335 }
2336 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002337 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002338 } finally {
2339 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002340 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002341
2342 if (isChanged) {
2343 synchronized (accounts.credentialsPermissionNotificationIds) {
2344 for (Pair<Pair<Account, String>, Integer> key
2345 : accounts.credentialsPermissionNotificationIds.keySet()) {
2346 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002347 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002348 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002349 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002350 account, uid, false));
2351 }
2352 }
2353 }
2354 }
2355
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002356 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002357 }
2358
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002359 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002360 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002361 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002362 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2363 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002364 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2365 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002366 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002367 + ", pid " + Binder.getCallingPid());
2368 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002369 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002370 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002371 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002372 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002373 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002374 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002375 accounts.accountsDb.beginTransaction();
2376 try {
2377 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2378 accounts.accountsDb.setTransactionSuccessful();
2379 } finally {
2380 accounts.accountsDb.endTransaction();
2381 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002382 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002383 for (Pair<Account, String> tokenInfo : deletedTokens) {
2384 Account act = tokenInfo.first;
2385 String tokenType = tokenInfo.second;
2386 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002387 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002388 // wipe out cached token in memory.
2389 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002390 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002391 }
Fred Quintana60307342009-03-24 22:48:12 -07002392 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002393 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002394 }
2395 }
2396
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002397 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002398 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002399 // TODO Move to AccountsDB
2400 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002401 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002402
Fred Quintana33269202009-04-20 16:05:10 -07002403 try {
2404 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002405 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002406 String accountName = cursor.getString(1);
2407 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002408 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002409 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002410 }
Fred Quintana33269202009-04-20 16:05:10 -07002411 } finally {
2412 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002413 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002414 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002415 }
2416
Carlos Valdivia91979be2015-05-22 14:11:35 -07002417 private void saveCachedToken(
2418 UserAccounts accounts,
2419 Account account,
2420 String callerPkg,
2421 byte[] callerSigDigest,
2422 String tokenType,
2423 String token,
2424 long expiryMillis) {
2425
2426 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2427 return;
2428 }
2429 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002430 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002431 synchronized (accounts.cacheLock) {
2432 accounts.accountTokenCaches.put(
2433 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002434 }
2435 }
2436
Amith Yamasani04e0d262012-02-14 11:50:53 -08002437 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2438 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002439 if (account == null || type == null) {
2440 return false;
2441 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002442 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002443 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002444 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002445 accounts.accountsDb.beginTransaction();
2446 boolean updateCache = false;
2447 try {
2448 long accountId = accounts.accountsDb.findDeAccountId(account);
2449 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002450 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002451 }
2452 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2453 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2454 accounts.accountsDb.setTransactionSuccessful();
2455 updateCache = true;
2456 return true;
2457 }
2458 return false;
2459 } finally {
2460 accounts.accountsDb.endTransaction();
2461 if (updateCache) {
2462 synchronized (accounts.cacheLock) {
2463 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2464 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002465 }
Fred Quintana33269202009-04-20 16:05:10 -07002466 }
Fred Quintana60307342009-03-24 22:48:12 -07002467 }
2468 }
2469
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002470 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002471 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002472 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002473 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2474 Log.v(TAG, "peekAuthToken: " + account
2475 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002476 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002477 + ", pid " + Binder.getCallingPid());
2478 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002479 Preconditions.checkNotNull(account, "account cannot be null");
2480 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002481 int userId = UserHandle.getCallingUserId();
2482 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002483 String msg = String.format(
2484 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2485 callingUid,
2486 account.type);
2487 throw new SecurityException(msg);
2488 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002489 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002490 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2491 + callingUid);
2492 return null;
2493 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002494 long identityToken = clearCallingIdentity();
2495 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002496 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002497 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002498 } finally {
2499 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002500 }
Fred Quintana60307342009-03-24 22:48:12 -07002501 }
2502
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002503 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002504 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002505 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002506 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2507 Log.v(TAG, "setAuthToken: " + account
2508 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002509 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002510 + ", pid " + Binder.getCallingPid());
2511 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002512 Preconditions.checkNotNull(account, "account cannot be null");
2513 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002514 int userId = UserHandle.getCallingUserId();
2515 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002516 String msg = String.format(
2517 "uid %s cannot set auth tokens associated with accounts of type: %s",
2518 callingUid,
2519 account.type);
2520 throw new SecurityException(msg);
2521 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002522 long identityToken = clearCallingIdentity();
2523 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002524 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002525 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002526 } finally {
2527 restoreCallingIdentity(identityToken);
2528 }
Fred Quintana60307342009-03-24 22:48:12 -07002529 }
2530
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002531 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002532 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002533 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002534 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2535 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002536 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002537 + ", pid " + Binder.getCallingPid());
2538 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002539 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002540 int userId = UserHandle.getCallingUserId();
2541 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002542 String msg = String.format(
2543 "uid %s cannot set secrets for accounts of type: %s",
2544 callingUid,
2545 account.type);
2546 throw new SecurityException(msg);
2547 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002548 long identityToken = clearCallingIdentity();
2549 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002550 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002551 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002552 } finally {
2553 restoreCallingIdentity(identityToken);
2554 }
Fred Quintana60307342009-03-24 22:48:12 -07002555 }
2556
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002557 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2558 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002559 if (account == null) {
2560 return;
2561 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002562 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002563 synchronized (accounts.dbLock) {
2564 synchronized (accounts.cacheLock) {
2565 accounts.accountsDb.beginTransaction();
2566 try {
2567 final long accountId = accounts.accountsDb.findDeAccountId(account);
2568 if (accountId >= 0) {
2569 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2570 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2571 accounts.authTokenCache.remove(account);
2572 accounts.accountTokenCaches.remove(account);
2573 accounts.accountsDb.setTransactionSuccessful();
2574 // If there is an account whose password will be updated and the database
2575 // transactions succeed, then we say that a change has occured. Even if the
2576 // new password is the same as the old and there were no authtokens to
2577 // delete.
2578 isChanged = true;
2579 String action = (password == null || password.length() == 0) ?
2580 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2581 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2582 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2583 callingUid);
2584 }
2585 } finally {
2586 accounts.accountsDb.endTransaction();
2587 if (isChanged) {
2588 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2589 sendNotificationAccountUpdated(account, accounts);
2590 sendAccountsChangedBroadcast(accounts.userId);
2591 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002592 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002593 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002594 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002595 }
2596
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002597 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002598 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002599 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002600 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2601 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002602 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002603 + ", pid " + Binder.getCallingPid());
2604 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002605 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002606 int userId = UserHandle.getCallingUserId();
2607 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002608 String msg = String.format(
2609 "uid %s cannot clear passwords for accounts of type: %s",
2610 callingUid,
2611 account.type);
2612 throw new SecurityException(msg);
2613 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002614 long identityToken = clearCallingIdentity();
2615 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002616 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002617 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002618 } finally {
2619 restoreCallingIdentity(identityToken);
2620 }
Fred Quintana60307342009-03-24 22:48:12 -07002621 }
2622
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002623 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002624 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002625 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002626 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2627 Log.v(TAG, "setUserData: " + account
2628 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002629 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002630 + ", pid " + Binder.getCallingPid());
2631 }
Fred Quintana382601f2010-03-25 12:25:10 -07002632 if (key == null) throw new IllegalArgumentException("key is null");
2633 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002634 int userId = UserHandle.getCallingUserId();
2635 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002636 String msg = String.format(
2637 "uid %s cannot set user data for accounts of type: %s",
2638 callingUid,
2639 account.type);
2640 throw new SecurityException(msg);
2641 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002642 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002643 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002644 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002645 if (!accountExistsCache(accounts, account)) {
2646 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002647 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002648 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002649 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002650 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002651 }
2652 }
2653
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002654 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2655 synchronized (accounts.cacheLock) {
2656 if (accounts.accountCache.containsKey(account.type)) {
2657 for (Account acc : accounts.accountCache.get(account.type)) {
2658 if (acc.name.equals(account.name)) {
2659 return true;
2660 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002661 }
2662 }
2663 }
2664 return false;
2665 }
2666
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002667 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002668 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002669 synchronized (accounts.dbLock) {
2670 accounts.accountsDb.beginTransaction();
2671 try {
2672 long accountId = accounts.accountsDb.findDeAccountId(account);
2673 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002674 return;
2675 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002676 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2677 if (extrasId < 0) {
2678 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2679 if (extrasId < 0) {
2680 return;
2681 }
2682 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2683 return;
2684 }
2685 accounts.accountsDb.setTransactionSuccessful();
2686 } finally {
2687 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002688 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002689 synchronized (accounts.cacheLock) {
2690 writeUserDataIntoCacheLocked(accounts, account, key, value);
2691 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002692 }
2693 }
2694
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002695 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002696 if (result == null) {
2697 Log.e(TAG, "the result is unexpectedly null", new Exception());
2698 }
2699 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2700 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2701 + response);
2702 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002703 try {
2704 response.onResult(result);
2705 } catch (RemoteException e) {
2706 // if the caller is dead then there is no one to care about remote
2707 // exceptions
2708 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2709 Log.v(TAG, "failure while notifying response", e);
2710 }
2711 }
2712 }
2713
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002714 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002715 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2716 final String authTokenType)
2717 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002718 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2719 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002720
Fred Quintanad9640ec2012-05-23 12:37:00 -07002721 final int callingUid = getCallingUid();
2722 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002723 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002724 throw new SecurityException("can only call from system");
2725 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002726 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002727 long identityToken = clearCallingIdentity();
2728 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002729 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002730 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2731 false /* stripAuthTokenFromResult */, null /* accountName */,
2732 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002733 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002734 protected String toDebugString(long now) {
2735 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002736 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002737 + ", authTokenType " + authTokenType;
2738 }
2739
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002740 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002741 public void run() throws RemoteException {
2742 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2743 }
2744
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002745 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002746 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002747 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002748 if (result != null) {
2749 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2750 Bundle bundle = new Bundle();
2751 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2752 super.onResult(bundle);
2753 return;
2754 } else {
2755 super.onResult(result);
2756 }
2757 }
2758 }.bind();
2759 } finally {
2760 restoreCallingIdentity(identityToken);
2761 }
2762 }
2763
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002764 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002765 public void getAuthToken(
2766 IAccountManagerResponse response,
2767 final Account account,
2768 final String authTokenType,
2769 final boolean notifyOnAuthFailure,
2770 final boolean expectActivityLaunch,
2771 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002772 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002773 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2774 Log.v(TAG, "getAuthToken: " + account
2775 + ", response " + response
2776 + ", authTokenType " + authTokenType
2777 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2778 + ", expectActivityLaunch " + expectActivityLaunch
2779 + ", caller's uid " + Binder.getCallingUid()
2780 + ", pid " + Binder.getCallingPid());
2781 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002782 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002783 try {
2784 if (account == null) {
2785 Slog.w(TAG, "getAuthToken called with null account");
2786 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2787 return;
2788 }
2789 if (authTokenType == null) {
2790 Slog.w(TAG, "getAuthToken called with null authTokenType");
2791 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2792 return;
2793 }
2794 } catch (RemoteException e) {
2795 Slog.w(TAG, "Failed to report error back to the client." + e);
2796 return;
2797 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002798 int userId = UserHandle.getCallingUserId();
2799 long ident = Binder.clearCallingIdentity();
2800 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002801 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002802 try {
2803 accounts = getUserAccounts(userId);
2804 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2805 AuthenticatorDescription.newKey(account.type), accounts.userId);
2806 } finally {
2807 Binder.restoreCallingIdentity(ident);
2808 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002809
Costin Manolachea40c6302010-12-13 14:50:45 -08002810 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002811 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002812
2813 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002814 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002815 final boolean permissionGranted =
2816 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002817
Carlos Valdivia91979be2015-05-22 14:11:35 -07002818 // Get the calling package. We will use it for the purpose of caching.
2819 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002820 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002821 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002822 try {
2823 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2824 } finally {
2825 Binder.restoreCallingIdentity(ident);
2826 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002827 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2828 String msg = String.format(
2829 "Uid %s is attempting to illegally masquerade as package %s!",
2830 callerUid,
2831 callerPkg);
2832 throw new SecurityException(msg);
2833 }
2834
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002835 // let authenticator know the identity of the caller
2836 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2837 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002838
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002839 if (notifyOnAuthFailure) {
2840 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002841 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002842
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002843 long identityToken = clearCallingIdentity();
2844 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002845 // Distill the caller's package signatures into a single digest.
2846 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2847
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002848 // if the caller has permission, do the peek. otherwise go the more expensive
2849 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002850 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002851 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002852 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002853 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002854 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2855 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2856 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002857 onResult(response, result);
2858 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002859 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002860 }
2861
Carlos Valdivia91979be2015-05-22 14:11:35 -07002862 if (customTokens) {
2863 /*
2864 * Look up tokens in the new cache only if the loginOptions don't have parameters
2865 * outside of those expected to be injected by the AccountManager, e.g.
2866 * ANDORID_PACKAGE_NAME.
2867 */
2868 String token = readCachedTokenInternal(
2869 accounts,
2870 account,
2871 authTokenType,
2872 callerPkg,
2873 callerPkgSigDigest);
2874 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002875 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2876 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2877 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002878 Bundle result = new Bundle();
2879 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2880 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2881 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2882 onResult(response, result);
2883 return;
2884 }
2885 }
2886
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002887 new Session(
2888 accounts,
2889 response,
2890 account.type,
2891 expectActivityLaunch,
2892 false /* stripAuthTokenFromResult */,
2893 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002894 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002895 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002896 protected String toDebugString(long now) {
2897 if (loginOptions != null) loginOptions.keySet();
2898 return super.toDebugString(now) + ", getAuthToken"
2899 + ", " + account
2900 + ", authTokenType " + authTokenType
2901 + ", loginOptions " + loginOptions
2902 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2903 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002904
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002905 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002906 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002907 // If the caller doesn't have permission then create and return the
2908 // "grant permission" intent instead of the "getAuthToken" intent.
2909 if (!permissionGranted) {
2910 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2911 } else {
2912 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2913 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002914 }
2915
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002916 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002917 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002918 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002919 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002920 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002921 Intent intent = newGrantCredentialsPermissionIntent(
2922 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002923 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002924 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002925 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002926 authTokenType,
2927 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002928 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002929 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002930 onResult(bundle);
2931 return;
2932 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002933 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002934 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002935 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2936 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002937 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002938 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002939 "the type and name should not be empty");
2940 return;
2941 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002942 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002943 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002944 saveAuthTokenToDatabase(
2945 mAccounts,
2946 resultAccount,
2947 authTokenType,
2948 authToken);
2949 }
2950 long expiryMillis = result.getLong(
2951 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2952 if (customTokens
2953 && expiryMillis > System.currentTimeMillis()) {
2954 saveCachedToken(
2955 mAccounts,
2956 account,
2957 callerPkg,
2958 callerPkgSigDigest,
2959 authTokenType,
2960 authToken,
2961 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002962 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002963 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002964
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002965 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002966 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002967 /*
2968 * Make sure that the supplied intent is owned by the authenticator
2969 * giving it to the system. Otherwise a malicious authenticator could
2970 * have users launching arbitrary activities by tricking users to
2971 * interact with malicious notifications.
2972 */
tiansiminga8868bf2017-09-20 13:59:13 +08002973 if (!checkKeyIntent(
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002974 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08002975 intent)) {
2976 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
2977 "invalid intent in bundle returned");
2978 return;
2979 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002980 doNotification(
2981 mAccounts,
2982 account,
2983 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002984 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002985 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002986 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002987 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002988 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002989 }.bind();
2990 } finally {
2991 restoreCallingIdentity(identityToken);
2992 }
Fred Quintana60307342009-03-24 22:48:12 -07002993 }
2994
Carlos Valdivia91979be2015-05-22 14:11:35 -07002995 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2996 MessageDigest digester;
2997 try {
2998 digester = MessageDigest.getInstance("SHA-256");
2999 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
3000 callerPkg, PackageManager.GET_SIGNATURES);
3001 for (Signature sig : pkgInfo.signatures) {
3002 digester.update(sig.toByteArray());
3003 }
3004 } catch (NoSuchAlgorithmException x) {
3005 Log.wtf(TAG, "SHA-256 should be available", x);
3006 digester = null;
3007 } catch (NameNotFoundException e) {
3008 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
3009 digester = null;
3010 }
3011 return (digester == null) ? null : digester.digest();
3012 }
3013
Dianne Hackborn41203752012-08-31 14:05:51 -07003014 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003015 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003016 int uid = intent.getIntExtra(
3017 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
3018 String authTokenType = intent.getStringExtra(
3019 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07003020 final String titleAndSubtitle =
3021 mContext.getString(R.string.permission_request_notification_with_subtitle,
3022 account.name);
3023 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07003024 String title = titleAndSubtitle;
3025 String subtitle = "";
3026 if (index > 0) {
3027 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04003028 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07003029 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07003030 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003031 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003032 Notification n =
3033 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
3034 .setSmallIcon(android.R.drawable.stat_sys_warning)
3035 .setWhen(0)
3036 .setColor(contextForUser.getColor(
3037 com.android.internal.R.color.system_notification_accent_color))
3038 .setContentTitle(title)
3039 .setContentText(subtitle)
3040 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
3041 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
3042 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07003043 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003044 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003045 }
3046
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003047 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
3048 int uid, AccountAuthenticatorResponse response, String authTokenType,
3049 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003050
3051 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003052
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003053 if (startInNewTask) {
3054 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
3055 // Since it was set in Eclair+ we can't change it without breaking apps using
3056 // the intent from a non-Activity context. This is the default behavior.
3057 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3058 }
Chris Wren717a8812017-03-31 15:34:39 -04003059 intent.addCategory(getCredentialPermissionNotificationId(account,
3060 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003061 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003062 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
3063 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003064 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08003065
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003066 return intent;
3067 }
3068
Chris Wren717a8812017-03-31 15:34:39 -04003069 private NotificationId getCredentialPermissionNotificationId(Account account,
3070 String authTokenType, int uid) {
3071 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07003072 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08003073 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003074 final Pair<Pair<Account, String>, Integer> key =
3075 new Pair<Pair<Account, String>, Integer>(
3076 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04003077 nId = accounts.credentialsPermissionNotificationIds.get(key);
3078 if (nId == null) {
3079 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
3080 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
3081 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
3082 nId = new NotificationId(tag, id);
3083 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003084 }
3085 }
Chris Wren717a8812017-03-31 15:34:39 -04003086 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003087 }
3088
Chris Wren717a8812017-03-31 15:34:39 -04003089 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
3090 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08003091 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04003092 nId = accounts.signinRequiredNotificationIds.get(account);
3093 if (nId == null) {
3094 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
3095 + ":" + account.hashCode();
3096 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
3097 nId = new NotificationId(tag, id);
3098 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003099 }
3100 }
Chris Wren717a8812017-03-31 15:34:39 -04003101 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07003102 }
3103
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003104 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07003105 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07003106 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003107 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003108 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003109 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3110 Log.v(TAG, "addAccount: accountType " + accountType
3111 + ", response " + response
3112 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003113 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08003114 + ", expectActivityLaunch " + expectActivityLaunch
3115 + ", caller's uid " + Binder.getCallingUid()
3116 + ", pid " + Binder.getCallingPid());
3117 }
Fred Quintana382601f2010-03-25 12:25:10 -07003118 if (response == null) throw new IllegalArgumentException("response is null");
3119 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003120
Amith Yamasani71e6c692013-03-24 17:39:28 -07003121 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003122 final int uid = Binder.getCallingUid();
3123 final int userId = UserHandle.getUserId(uid);
3124 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003125 try {
3126 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3127 "User is not allowed to add an account!");
3128 } catch (RemoteException re) {
3129 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003130 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003131 return;
3132 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003133 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003134 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003135 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3136 "User cannot modify accounts of this type (policy).");
3137 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07003138 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003139 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3140 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003141 return;
3142 }
3143
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003144 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07003145 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3146 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3147 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3148
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003149 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003150 long identityToken = clearCallingIdentity();
3151 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003152 UserAccounts accounts = getUserAccounts(usrId);
3153 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003154 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3155 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003156 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003157 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003158 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003159 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003160 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003161 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003162 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003163 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003164
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003165 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003166 protected String toDebugString(long now) {
3167 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003168 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003169 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003170 }
3171 }.bind();
3172 } finally {
3173 restoreCallingIdentity(identityToken);
3174 }
Fred Quintana60307342009-03-24 22:48:12 -07003175 }
3176
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003177 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003178 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3179 final String authTokenType, final String[] requiredFeatures,
3180 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003181 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003182 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003183 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3184 Log.v(TAG, "addAccount: accountType " + accountType
3185 + ", response " + response
3186 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003187 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003188 + ", expectActivityLaunch " + expectActivityLaunch
3189 + ", caller's uid " + Binder.getCallingUid()
3190 + ", pid " + Binder.getCallingPid()
3191 + ", for user id " + userId);
3192 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003193 Preconditions.checkArgument(response != null, "response cannot be null");
3194 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003195 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003196 if (isCrossUser(callingUid, userId)) {
3197 throw new SecurityException(
3198 String.format(
3199 "User %s trying to add account for %s" ,
3200 UserHandle.getCallingUserId(),
3201 userId));
3202 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003203
3204 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003205 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003206 try {
3207 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3208 "User is not allowed to add an account!");
3209 } catch (RemoteException re) {
3210 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003211 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003212 return;
3213 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003214 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003215 try {
3216 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3217 "User cannot modify accounts of this type (policy).");
3218 } catch (RemoteException re) {
3219 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003220 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3221 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003222 return;
3223 }
3224
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003225 final int pid = Binder.getCallingPid();
3226 final int uid = Binder.getCallingUid();
3227 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3228 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3229 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3230
3231 long identityToken = clearCallingIdentity();
3232 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003233 UserAccounts accounts = getUserAccounts(userId);
3234 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003235 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3236 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003237 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003238 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003239 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003240 @Override
3241 public void run() throws RemoteException {
3242 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3243 options);
3244 }
3245
3246 @Override
3247 protected String toDebugString(long now) {
3248 return super.toDebugString(now) + ", addAccount"
3249 + ", accountType " + accountType
3250 + ", requiredFeatures "
3251 + (requiredFeatures != null
3252 ? TextUtils.join(",", requiredFeatures)
3253 : null);
3254 }
3255 }.bind();
3256 } finally {
3257 restoreCallingIdentity(identityToken);
3258 }
3259 }
3260
Sandra Kwan78812282015-11-04 11:19:47 -08003261 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003262 public void startAddAccountSession(
3263 final IAccountManagerResponse response,
3264 final String accountType,
3265 final String authTokenType,
3266 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003267 final boolean expectActivityLaunch,
3268 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003269 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003270 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3271 Log.v(TAG,
3272 "startAddAccountSession: accountType " + accountType
3273 + ", response " + response
3274 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003275 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003276 + ", expectActivityLaunch " + expectActivityLaunch
3277 + ", caller's uid " + Binder.getCallingUid()
3278 + ", pid " + Binder.getCallingPid());
3279 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003280 Preconditions.checkArgument(response != null, "response cannot be null");
3281 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003282
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003283 final int uid = Binder.getCallingUid();
3284 final int userId = UserHandle.getUserId(uid);
3285 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003286 try {
3287 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3288 "User is not allowed to add an account!");
3289 } catch (RemoteException re) {
3290 }
3291 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3292 return;
3293 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003294 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003295 try {
3296 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3297 "User cannot modify accounts of this type (policy).");
3298 } catch (RemoteException re) {
3299 }
3300 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3301 userId);
3302 return;
3303 }
Sandra Kwan78812282015-11-04 11:19:47 -08003304 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003305 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3306 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3307 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3308
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003309 // Check to see if the Password should be included to the caller.
3310 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3311 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003312 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003313
Sandra Kwan78812282015-11-04 11:19:47 -08003314 long identityToken = clearCallingIdentity();
3315 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003316 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003317 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3318 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003319 new StartAccountSession(
3320 accounts,
3321 response,
3322 accountType,
3323 expectActivityLaunch,
3324 null /* accountName */,
3325 false /* authDetailsRequired */,
3326 true /* updateLastAuthenticationTime */,
3327 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003328 @Override
3329 public void run() throws RemoteException {
3330 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3331 requiredFeatures, options);
3332 }
3333
3334 @Override
3335 protected String toDebugString(long now) {
3336 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3337 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3338 + accountType + ", requiredFeatures "
3339 + (requiredFeatures != null ? requiredFeaturesStr : null);
3340 }
3341 }.bind();
3342 } finally {
3343 restoreCallingIdentity(identityToken);
3344 }
3345 }
3346
3347 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3348 private abstract class StartAccountSession extends Session {
3349
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003350 private final boolean mIsPasswordForwardingAllowed;
3351
3352 public StartAccountSession(
3353 UserAccounts accounts,
3354 IAccountManagerResponse response,
3355 String accountType,
3356 boolean expectActivityLaunch,
3357 String accountName,
3358 boolean authDetailsRequired,
3359 boolean updateLastAuthenticationTime,
3360 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003361 super(accounts, response, accountType, expectActivityLaunch,
3362 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3363 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003364 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003365 }
3366
3367 @Override
3368 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003369 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003370 mNumResults++;
3371 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003372 if (result != null
3373 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08003374 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003375 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08003376 intent)) {
3377 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
3378 "invalid intent in bundle returned");
3379 return;
3380 }
Sandra Kwan78812282015-11-04 11:19:47 -08003381 }
Sandra Kwan78812282015-11-04 11:19:47 -08003382 IAccountManagerResponse response;
3383 if (mExpectActivityLaunch && result != null
3384 && result.containsKey(AccountManager.KEY_INTENT)) {
3385 response = mResponse;
3386 } else {
3387 response = getResponseAndClose();
3388 }
3389 if (response == null) {
3390 return;
3391 }
3392 if (result == null) {
3393 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3394 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3395 + response);
3396 }
3397 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3398 "null bundle returned");
3399 return;
3400 }
3401
3402 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3403 // All AccountManager error codes are greater
3404 // than 0
3405 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3406 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3407 return;
3408 }
3409
Hongming Jin368aa192016-07-29 14:29:54 -07003410 // Omit passwords if the caller isn't permitted to see them.
3411 if (!mIsPasswordForwardingAllowed) {
3412 result.remove(AccountManager.KEY_PASSWORD);
3413 }
3414
Sandra Kwan78812282015-11-04 11:19:47 -08003415 // Strip auth token from result.
3416 result.remove(AccountManager.KEY_AUTHTOKEN);
3417
3418 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3419 Log.v(TAG,
3420 getClass().getSimpleName() + " calling onResult() on response " + response);
3421 }
3422
3423 // Get the session bundle created by authenticator. The
3424 // bundle contains data necessary for finishing the session
3425 // later. The session bundle will be encrypted here and
3426 // decrypted later when trying to finish the session.
3427 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3428 if (sessionBundle != null) {
3429 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3430 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003431 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003432 Log.w(TAG, "Account type in session bundle doesn't match request.");
3433 }
3434 // Add accountType info to session bundle. This will
3435 // override any value set by authenticator.
3436 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3437
3438 // Encrypt session bundle before returning to caller.
3439 try {
3440 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3441 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3442 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3443 } catch (GeneralSecurityException e) {
3444 if (Log.isLoggable(TAG, Log.DEBUG)) {
3445 Log.v(TAG, "Failed to encrypt session bundle!", e);
3446 }
3447 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3448 "failed to encrypt session bundle");
3449 return;
3450 }
3451 }
3452
3453 sendResponse(response, result);
3454 }
3455 }
3456
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003457 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003458 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003459 @NonNull Bundle sessionBundle,
3460 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003461 Bundle appInfo,
3462 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003463 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003464 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003465 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3466 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003467 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003468 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003469 + ", caller's uid " + callingUid
3470 + ", caller's user id " + UserHandle.getCallingUserId()
3471 + ", pid " + Binder.getCallingPid()
3472 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003473 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003474 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003475 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3476 // Account type is added to it before encryption.
3477 if (sessionBundle == null || sessionBundle.size() == 0) {
3478 throw new IllegalArgumentException("sessionBundle is empty");
3479 }
3480
Dmitry Dementyev52745472016-12-02 10:27:45 -08003481 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003482 if (isCrossUser(callingUid, userId)) {
3483 throw new SecurityException(
3484 String.format(
3485 "User %s trying to finish session for %s without cross user permission",
3486 UserHandle.getCallingUserId(),
3487 userId));
3488 }
3489
Sandra Kwan0b84b452016-01-20 15:25:42 -08003490 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003491 sendErrorResponse(response,
3492 AccountManager.ERROR_CODE_USER_RESTRICTED,
3493 "User is not allowed to add an account!");
3494 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3495 return;
3496 }
3497
3498 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003499 final Bundle decryptedBundle;
3500 final String accountType;
3501 // First decrypt session bundle to get account type for checking permission.
3502 try {
3503 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3504 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3505 if (decryptedBundle == null) {
3506 sendErrorResponse(
3507 response,
3508 AccountManager.ERROR_CODE_BAD_REQUEST,
3509 "failed to decrypt session bundle");
3510 return;
3511 }
3512 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3513 // Account type cannot be null. This should not happen if session bundle was created
3514 // properly by #StartAccountSession.
3515 if (TextUtils.isEmpty(accountType)) {
3516 sendErrorResponse(
3517 response,
3518 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3519 "accountType is empty");
3520 return;
3521 }
3522
3523 // If by any chances, decryptedBundle contains colliding keys with
3524 // system info
3525 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3526 // update credentials flow, we should replace with the new values of the current call.
3527 if (appInfo != null) {
3528 decryptedBundle.putAll(appInfo);
3529 }
3530
3531 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003532 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003533 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3534 } catch (GeneralSecurityException e) {
3535 if (Log.isLoggable(TAG, Log.DEBUG)) {
3536 Log.v(TAG, "Failed to decrypt session bundle!", e);
3537 }
3538 sendErrorResponse(
3539 response,
3540 AccountManager.ERROR_CODE_BAD_REQUEST,
3541 "failed to decrypt session bundle");
3542 return;
3543 }
3544
Sandra Kwan0b84b452016-01-20 15:25:42 -08003545 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003546 sendErrorResponse(
3547 response,
3548 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3549 "User cannot modify accounts of this type (policy).");
3550 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3551 userId);
3552 return;
3553 }
3554
3555 long identityToken = clearCallingIdentity();
3556 try {
3557 UserAccounts accounts = getUserAccounts(userId);
3558 logRecordWithUid(
3559 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003560 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3561 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003562 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003563 new Session(
3564 accounts,
3565 response,
3566 accountType,
3567 expectActivityLaunch,
3568 true /* stripAuthTokenFromResult */,
3569 null /* accountName */,
3570 false /* authDetailsRequired */,
3571 true /* updateLastAuthenticationTime */) {
3572 @Override
3573 public void run() throws RemoteException {
3574 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3575 }
3576
3577 @Override
3578 protected String toDebugString(long now) {
3579 return super.toDebugString(now)
3580 + ", finishSession"
3581 + ", accountType " + accountType;
3582 }
3583 }.bind();
3584 } finally {
3585 restoreCallingIdentity(identityToken);
3586 }
3587 }
3588
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003589 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003590 final DevicePolicyManagerInternal dpmi =
3591 LocalServices.getService(DevicePolicyManagerInternal.class);
3592 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003593 if (dpmi == null) {
3594 intent = getDefaultCantAddAccountIntent(errorCode);
3595 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003596 intent = dpmi.createUserRestrictionSupportIntent(userId,
3597 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3598 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3599 intent = dpmi.createShowAdminSupportIntent(userId, false);
3600 }
3601 if (intent == null) {
3602 intent = getDefaultCantAddAccountIntent(errorCode);
3603 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003604 long identityToken = clearCallingIdentity();
3605 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003606 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003607 } finally {
3608 restoreCallingIdentity(identityToken);
3609 }
3610 }
3611
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003612 /**
3613 * Called when we don't know precisely who is preventing us from adding an account.
3614 */
3615 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3616 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3617 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3618 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3619 return cantAddAccount;
3620 }
3621
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003622 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003623 public void confirmCredentialsAsUser(
3624 IAccountManagerResponse response,
3625 final Account account,
3626 final Bundle options,
3627 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003628 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003629 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003630 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003631 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3632 Log.v(TAG, "confirmCredentials: " + account
3633 + ", response " + response
3634 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003635 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003636 + ", pid " + Binder.getCallingPid());
3637 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003638 // Only allow the system process to read accounts of other users
3639 if (isCrossUser(callingUid, userId)) {
3640 throw new SecurityException(
3641 String.format(
3642 "User %s trying to confirm account credentials for %s" ,
3643 UserHandle.getCallingUserId(),
3644 userId));
3645 }
Fred Quintana382601f2010-03-25 12:25:10 -07003646 if (response == null) throw new IllegalArgumentException("response is null");
3647 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003648 long identityToken = clearCallingIdentity();
3649 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003650 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003651 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003652 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003653 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003654 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003655 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003656 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003657 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003658 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003659 protected String toDebugString(long now) {
3660 return super.toDebugString(now) + ", confirmCredentials"
3661 + ", " + account;
3662 }
3663 }.bind();
3664 } finally {
3665 restoreCallingIdentity(identityToken);
3666 }
Fred Quintana60307342009-03-24 22:48:12 -07003667 }
3668
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003669 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003670 public void updateCredentials(IAccountManagerResponse response, final Account account,
3671 final String authTokenType, final boolean expectActivityLaunch,
3672 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003673 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003674 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3675 Log.v(TAG, "updateCredentials: " + account
3676 + ", response " + response
3677 + ", authTokenType " + authTokenType
3678 + ", expectActivityLaunch " + expectActivityLaunch
3679 + ", caller's uid " + Binder.getCallingUid()
3680 + ", pid " + Binder.getCallingPid());
3681 }
Fred Quintana382601f2010-03-25 12:25:10 -07003682 if (response == null) throw new IllegalArgumentException("response is null");
3683 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003684 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003685 long identityToken = clearCallingIdentity();
3686 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003687 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003688 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003689 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003690 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003691 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003692 public void run() throws RemoteException {
3693 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3694 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003695 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003696 protected String toDebugString(long now) {
3697 if (loginOptions != null) loginOptions.keySet();
3698 return super.toDebugString(now) + ", updateCredentials"
3699 + ", " + account
3700 + ", authTokenType " + authTokenType
3701 + ", loginOptions " + loginOptions;
3702 }
3703 }.bind();
3704 } finally {
3705 restoreCallingIdentity(identityToken);
3706 }
Fred Quintana60307342009-03-24 22:48:12 -07003707 }
3708
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003709 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003710 public void startUpdateCredentialsSession(
3711 IAccountManagerResponse response,
3712 final Account account,
3713 final String authTokenType,
3714 final boolean expectActivityLaunch,
3715 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003716 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003717 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3718 Log.v(TAG,
3719 "startUpdateCredentialsSession: " + account + ", response " + response
3720 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3721 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3722 + ", pid " + Binder.getCallingPid());
3723 }
3724 if (response == null) {
3725 throw new IllegalArgumentException("response is null");
3726 }
3727 if (account == null) {
3728 throw new IllegalArgumentException("account is null");
3729 }
Sandra Kwana578d112015-12-16 16:01:43 -08003730
3731 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003732 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003733
3734 // Check to see if the Password should be included to the caller.
3735 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3736 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003737 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003738
Sandra Kwane68c37e2015-11-12 17:11:49 -08003739 long identityToken = clearCallingIdentity();
3740 try {
3741 UserAccounts accounts = getUserAccounts(userId);
3742 new StartAccountSession(
3743 accounts,
3744 response,
3745 account.type,
3746 expectActivityLaunch,
3747 account.name,
3748 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003749 true /* updateLastCredentialTime */,
3750 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003751 @Override
3752 public void run() throws RemoteException {
3753 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3754 loginOptions);
3755 }
3756
3757 @Override
3758 protected String toDebugString(long now) {
3759 if (loginOptions != null)
3760 loginOptions.keySet();
3761 return super.toDebugString(now)
3762 + ", startUpdateCredentialsSession"
3763 + ", " + account
3764 + ", authTokenType " + authTokenType
3765 + ", loginOptions " + loginOptions;
3766 }
3767 }.bind();
3768 } finally {
3769 restoreCallingIdentity(identityToken);
3770 }
3771 }
3772
3773 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003774 public void isCredentialsUpdateSuggested(
3775 IAccountManagerResponse response,
3776 final Account account,
3777 final String statusToken) {
3778 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3779 Log.v(TAG,
3780 "isCredentialsUpdateSuggested: " + account + ", response " + response
3781 + ", caller's uid " + Binder.getCallingUid()
3782 + ", pid " + Binder.getCallingPid());
3783 }
3784 if (response == null) {
3785 throw new IllegalArgumentException("response is null");
3786 }
3787 if (account == null) {
3788 throw new IllegalArgumentException("account is null");
3789 }
3790 if (TextUtils.isEmpty(statusToken)) {
3791 throw new IllegalArgumentException("status token is empty");
3792 }
3793
Sandra Kwan390c9d22016-01-12 14:13:37 -08003794 int usrId = UserHandle.getCallingUserId();
3795 long identityToken = clearCallingIdentity();
3796 try {
3797 UserAccounts accounts = getUserAccounts(usrId);
3798 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3799 false /* stripAuthTokenFromResult */, account.name,
3800 false /* authDetailsRequired */) {
3801 @Override
3802 protected String toDebugString(long now) {
3803 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3804 + ", " + account;
3805 }
3806
3807 @Override
3808 public void run() throws RemoteException {
3809 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3810 }
3811
3812 @Override
3813 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003814 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003815 IAccountManagerResponse response = getResponseAndClose();
3816 if (response == null) {
3817 return;
3818 }
3819
3820 if (result == null) {
3821 sendErrorResponse(
3822 response,
3823 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3824 "null bundle");
3825 return;
3826 }
3827
3828 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3829 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3830 + response);
3831 }
3832 // Check to see if an error occurred. We know if an error occurred because all
3833 // error codes are greater than 0.
3834 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3835 sendErrorResponse(response,
3836 result.getInt(AccountManager.KEY_ERROR_CODE),
3837 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3838 return;
3839 }
3840 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3841 sendErrorResponse(
3842 response,
3843 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3844 "no result in response");
3845 return;
3846 }
3847 final Bundle newResult = new Bundle();
3848 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3849 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3850 sendResponse(response, newResult);
3851 }
3852 }.bind();
3853 } finally {
3854 restoreCallingIdentity(identityToken);
3855 }
3856 }
3857
3858 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003859 public void editProperties(IAccountManagerResponse response, final String accountType,
3860 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003861 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003862 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3863 Log.v(TAG, "editProperties: accountType " + accountType
3864 + ", response " + response
3865 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003866 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003867 + ", pid " + Binder.getCallingPid());
3868 }
Fred Quintana382601f2010-03-25 12:25:10 -07003869 if (response == null) throw new IllegalArgumentException("response is null");
3870 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003871 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003872 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3873 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003874 String msg = String.format(
3875 "uid %s cannot edit authenticator properites for account type: %s",
3876 callingUid,
3877 accountType);
3878 throw new SecurityException(msg);
3879 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003880 long identityToken = clearCallingIdentity();
3881 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003882 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003883 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003884 true /* stripAuthTokenFromResult */, null /* accountName */,
3885 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003886 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003887 public void run() throws RemoteException {
3888 mAuthenticator.editProperties(this, mAccountType);
3889 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003890 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003891 protected String toDebugString(long now) {
3892 return super.toDebugString(now) + ", editProperties"
3893 + ", accountType " + accountType;
3894 }
3895 }.bind();
3896 } finally {
3897 restoreCallingIdentity(identityToken);
3898 }
Fred Quintana60307342009-03-24 22:48:12 -07003899 }
3900
Amith Yamasani12747872015-12-07 14:19:49 -08003901 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003902 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3903 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003904 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003905 throw new SecurityException("Can be called only by system UID");
3906 }
3907 Preconditions.checkNotNull(account, "account cannot be null");
3908 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3909 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3910
3911 final int userId = userHandle.getIdentifier();
3912
3913 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3914
3915 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003916 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003917 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003918 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003919 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003920 return false;
3921 }
3922 }
3923
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003924 // Returns package with oldest target SDK for given UID.
3925 private String getPackageNameForUid(int uid) {
3926 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3927 if (ArrayUtils.isEmpty(packageNames)) {
3928 return null;
3929 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003930 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003931 if (packageNames.length == 1) {
3932 return packageName;
3933 }
3934 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003935 int oldestVersion = Integer.MAX_VALUE;
3936 for (String name : packageNames) {
3937 try {
3938 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3939 if (applicationInfo != null) {
3940 int version = applicationInfo.targetSdkVersion;
3941 if (version < oldestVersion) {
3942 oldestVersion = version;
3943 packageName = name;
3944 }
3945 }
3946 } catch (NameNotFoundException e) {
3947 // skip
3948 }
3949 }
3950 return packageName;
3951 }
3952
Svet Ganovf6d424f12016-09-20 20:18:53 -07003953 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3954 int uid) {
3955 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003956 packageName = getPackageNameForUid(uid);
3957 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003958 return false;
3959 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003960 }
3961
3962 // Use null token which means any token. Having a token means the package
3963 // is trusted by the authenticator, hence it is fine to access the account.
3964 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3965 return true;
3966 }
3967 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003968 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003969
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003970 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003971 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003972 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003973 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003974 }
3975
3976 @Override
3977 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3978 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003979 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003980 throw new SecurityException("Can be called only by system UID");
3981 }
3982
3983 Preconditions.checkNotNull(account, "account cannot be null");
3984 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3985 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3986
3987 final int userId = userHandle.getIdentifier();
3988
3989 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3990
3991 final int uid;
3992 try {
3993 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3994 } catch (NameNotFoundException e) {
3995 Slog.e(TAG, "Unknown package " + packageName);
3996 return null;
3997 }
3998
3999 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
4000
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07004001 final long identity = Binder.clearCallingIdentity();
4002 try {
4003 return PendingIntent.getActivityAsUser(
4004 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
4005 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
4006 null, new UserHandle(userId)).getIntentSender();
4007 } finally {
4008 Binder.restoreCallingIdentity(identity);
4009 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004010 }
4011
4012 private Intent newRequestAccountAccessIntent(Account account, String packageName,
4013 int uid, RemoteCallback callback) {
4014 return newGrantCredentialsPermissionIntent(account, packageName, uid,
4015 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
4016 @Override
4017 public void onResult(Bundle value) throws RemoteException {
4018 handleAuthenticatorResponse(true);
4019 }
4020
4021 @Override
4022 public void onRequestContinued() {
4023 /* ignore */
4024 }
4025
4026 @Override
4027 public void onError(int errorCode, String errorMessage) throws RemoteException {
4028 handleAuthenticatorResponse(false);
4029 }
4030
4031 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
4032 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07004033 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004034 UserHandle.getUserHandleForUid(uid));
4035 if (callback != null) {
4036 Bundle result = new Bundle();
4037 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
4038 callback.sendResult(result);
4039 }
4040 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07004041 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004042 }
4043
4044 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08004045 public boolean someUserHasAccount(@NonNull final Account account) {
4046 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
4047 throw new SecurityException("Only system can check for accounts across users");
4048 }
4049 final long token = Binder.clearCallingIdentity();
4050 try {
4051 AccountAndUser[] allAccounts = getAllAccounts();
4052 for (int i = allAccounts.length - 1; i >= 0; i--) {
4053 if (allAccounts[i].account.equals(account)) {
4054 return true;
4055 }
4056 }
4057 return false;
4058 } finally {
4059 Binder.restoreCallingIdentity(token);
4060 }
4061 }
4062
Fred Quintana33269202009-04-20 16:05:10 -07004063 private class GetAccountsByTypeAndFeatureSession extends Session {
4064 private final String[] mFeatures;
4065 private volatile Account[] mAccountsOfType = null;
4066 private volatile ArrayList<Account> mAccountsWithFeatures = null;
4067 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004068 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004069 private final String mPackageName;
sunjianf29d5492017-05-11 15:42:31 -07004070 private final boolean mIncludeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004071
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004072 public GetAccountsByTypeAndFeatureSession(
4073 UserAccounts accounts,
4074 IAccountManagerResponse response,
4075 String type,
4076 String[] features,
4077 int callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004078 String packageName,
4079 boolean includeManagedNotVisible) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08004080 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004081 true /* stripAuthTokenFromResult */, null /* accountName */,
4082 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004083 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07004084 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004085 mPackageName = packageName;
sunjianf29d5492017-05-11 15:42:31 -07004086 mIncludeManagedNotVisible = includeManagedNotVisible;
Fred Quintana33269202009-04-20 16:05:10 -07004087 }
4088
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004089 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004090 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004091 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
sunjianf29d5492017-05-11 15:42:31 -07004092 mCallingUid, mPackageName, mIncludeManagedNotVisible);
Fred Quintana33269202009-04-20 16:05:10 -07004093 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07004094 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07004095 mCurrentAccount = 0;
4096
4097 checkAccount();
4098 }
4099
4100 public void checkAccount() {
4101 if (mCurrentAccount >= mAccountsOfType.length) {
4102 sendResult();
4103 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07004104 }
Fred Quintana33269202009-04-20 16:05:10 -07004105
Fred Quintana29e94b82010-03-10 12:11:51 -08004106 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
4107 if (accountAuthenticator == null) {
4108 // It is possible that the authenticator has died, which is indicated by
4109 // mAuthenticator being set to null. If this happens then just abort.
4110 // There is no need to send back a result or error in this case since
4111 // that already happened when mAuthenticator was cleared.
4112 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4113 Log.v(TAG, "checkAccount: aborting session since we are no longer"
4114 + " connected to the authenticator, " + toDebugString());
4115 }
4116 return;
4117 }
Fred Quintana33269202009-04-20 16:05:10 -07004118 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08004119 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07004120 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004121 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07004122 }
4123 }
4124
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004125 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004126 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004127 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07004128 mNumResults++;
4129 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004130 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07004131 return;
4132 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004133 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07004134 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
4135 }
4136 mCurrentAccount++;
4137 checkAccount();
4138 }
4139
4140 public void sendResult() {
4141 IAccountManagerResponse response = getResponseAndClose();
4142 if (response != null) {
4143 try {
4144 Account[] accounts = new Account[mAccountsWithFeatures.size()];
4145 for (int i = 0; i < accounts.length; i++) {
4146 accounts[i] = mAccountsWithFeatures.get(i);
4147 }
Fred Quintana56285a62010-12-02 14:20:51 -08004148 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4149 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
4150 + response);
4151 }
Fred Quintana33269202009-04-20 16:05:10 -07004152 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004153 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07004154 response.onResult(result);
4155 } catch (RemoteException e) {
4156 // if the caller is dead then there is no one to care about remote exceptions
4157 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4158 Log.v(TAG, "failure while notifying response", e);
4159 }
4160 }
4161 }
4162 }
4163
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004164 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004165 protected String toDebugString(long now) {
4166 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4167 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4168 }
4169 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004170
Amith Yamasani04e0d262012-02-14 11:50:53 -08004171 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004172 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004173 * @hide
4174 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004175 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004176 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004177 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004178 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004179 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4180 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004181 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004182 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004183 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004184 long identityToken = clearCallingIdentity();
4185 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004186 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004187 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004188 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004189 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004190 opPackageName,
4191 visibleAccountTypes,
4192 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004193 } finally {
4194 restoreCallingIdentity(identityToken);
4195 }
4196 }
4197
Amith Yamasanif29f2362012-04-05 18:29:52 -07004198 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004199 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004200 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004201 * @hide
4202 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004203 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004204 public AccountAndUser[] getRunningAccounts() {
4205 final int[] runningUserIds;
4206 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004207 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004208 } catch (RemoteException e) {
4209 // Running in system_server; should never happen
4210 throw new RuntimeException(e);
4211 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004212 return getAccounts(runningUserIds);
4213 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004214
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004215 /**
4216 * Returns accounts for all users, ignores visibility values.
4217 *
4218 * @hide
4219 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004220 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004221 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004222 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004223 final int[] userIds = new int[users.size()];
4224 for (int i = 0; i < userIds.length; i++) {
4225 userIds[i] = users.get(i).id;
4226 }
4227 return getAccounts(userIds);
4228 }
4229
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004230 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004231 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004232 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004233 for (int userId : userIds) {
4234 UserAccounts userAccounts = getUserAccounts(userId);
4235 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004236 Account[] accounts = getAccountsFromCache(
4237 userAccounts,
4238 null /* type */,
4239 Binder.getCallingUid(),
4240 null /* packageName */,
4241 false /* include managed not visible*/);
4242 for (Account account : accounts) {
4243 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004244 }
4245 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004246
4247 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4248 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004249 }
4250
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004251 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004252 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004253 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004254 int callingUid = Binder.getCallingUid();
4255 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004256 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004257 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004258 }
4259
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004260 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004261 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004262 String type,
4263 int userId,
4264 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004265 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004266 String opPackageName,
4267 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004268 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004269 // Only allow the system process to read accounts of other users
4270 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004271 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004272 && mContext.checkCallingOrSelfPermission(
4273 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4274 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004275 throw new SecurityException("User " + UserHandle.getCallingUserId()
4276 + " trying to get account for " + userId);
4277 }
4278
Fred Quintana56285a62010-12-02 14:20:51 -08004279 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4280 Log.v(TAG, "getAccounts: accountType " + type
4281 + ", caller's uid " + Binder.getCallingUid()
4282 + ", pid " + Binder.getCallingPid());
4283 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004284
4285 // If the original calling app was using account choosing activity
4286 // provided by the framework or authenticator we'll passing in
4287 // the original caller's uid here, which is what should be used for filtering.
4288 List<String> managedTypes =
4289 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4290 if (packageUid != -1 &&
4291 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4292 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004293 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004294 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004295 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004296 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4297 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004298 if (visibleAccountTypes.isEmpty()
4299 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004300 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004301 } else if (visibleAccountTypes.contains(type)) {
4302 // Prune the list down to just the requested type.
4303 visibleAccountTypes = new ArrayList<>();
4304 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004305 } // else aggregate all the visible accounts (it won't matter if the
4306 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004307
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004308 long identityToken = clearCallingIdentity();
4309 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004310 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004311 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004312 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004313 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004314 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004315 visibleAccountTypes,
4316 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004317 } finally {
4318 restoreCallingIdentity(identityToken);
4319 }
4320 }
4321
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004322 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004323 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004324 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004325 int callingUid,
4326 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004327 List<String> visibleAccountTypes,
4328 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004329 ArrayList<Account> visibleAccounts = new ArrayList<>();
4330 for (String visibleType : visibleAccountTypes) {
4331 Account[] accountsForType = getAccountsFromCache(
4332 userAccounts, visibleType, callingUid, callingPackage,
4333 includeUserManagedNotVisible);
4334 if (accountsForType != null) {
4335 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004336 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004337 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004338 Account[] result = new Account[visibleAccounts.size()];
4339 for (int i = 0; i < visibleAccounts.size(); i++) {
4340 result[i] = visibleAccounts.get(i);
4341 }
4342 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004343 }
4344
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004345 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004346 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4347 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004348 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004349 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004350 for (Account account : accounts) {
4351 addSharedAccountAsUser(account, userId);
4352 }
4353 }
4354
4355 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004356 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004357 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004358 accounts.accountsDb.deleteSharedAccount(account);
4359 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004360 if (accountId < 0) {
4361 Log.w(TAG, "insertAccountIntoDatabase: " + account
4362 + ", skipping the DB insert failed");
4363 return false;
4364 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004365 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4366 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004367 return true;
4368 }
4369
4370 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004371 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4372 userId = handleIncomingUser(userId);
4373 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004374 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4375 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004376 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004377 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004378 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004379 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004380 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004381 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004382 }
4383 return r > 0;
4384 }
4385
4386 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004387 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004388 return removeSharedAccountAsUser(account, userId, getCallingUid());
4389 }
4390
4391 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004392 userId = handleIncomingUser(userId);
4393 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004394 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4395 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004396 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004397 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004398 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004399 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004400 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004401 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004402 }
4403
4404 @Override
4405 public Account[] getSharedAccountsAsUser(int userId) {
4406 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004407 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004408 synchronized (accounts.dbLock) {
4409 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4410 Account[] accountArray = new Account[accountList.size()];
4411 accountList.toArray(accountArray);
4412 return accountArray;
4413 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004414 }
4415
4416 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004417 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004418 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004419 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004420 }
4421
Amith Yamasani27db4682013-03-30 17:07:47 -07004422 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004423 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004424 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004425 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004426 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004427 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004428 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4429 + callingUid + " with uid=" + uid);
4430 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004431 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004432 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004433 }
4434
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004435 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004436 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004437 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4438 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004439 int callingUid = Binder.getCallingUid();
4440 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004441 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004442 int packageUid = -1;
4443 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004444 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4445 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004446 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004447 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004448 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004449 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004450 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4451 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004452 }
sunjiand62dc392017-06-01 12:05:59 -07004453 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
4454 return getAccountsAsUserForPackage(type, userId,
4455 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
4456 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004457 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004458 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004459 }
4460
sunjianf29d5492017-05-11 15:42:31 -07004461 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
4462 if (accounts.length < 1) return false;
4463 if (accounts.length > 1) return true;
4464 Account account = accounts[0];
4465 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
4466 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
4467 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
4468 return false;
4469 }
4470
4471 private void startChooseAccountActivityWithAccounts(
sunjianbdabd402017-06-06 17:54:07 -07004472 IAccountManagerResponse response, Account[] accounts, String callingPackage) {
sunjianf29d5492017-05-11 15:42:31 -07004473 Intent intent = new Intent(mContext, ChooseAccountActivity.class);
4474 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
4475 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
4476 new AccountManagerResponse(response));
sunjianbdabd402017-06-06 17:54:07 -07004477 intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004478
4479 mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
4480 }
4481
4482 private void handleGetAccountsResult(
4483 IAccountManagerResponse response,
4484 Account[] accounts,
4485 String callingPackage) {
4486
4487 if (needToStartChooseAccountActivity(accounts, callingPackage)) {
sunjianbdabd402017-06-06 17:54:07 -07004488 startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
sunjianf29d5492017-05-11 15:42:31 -07004489 return;
4490 }
4491 if (accounts.length == 1) {
4492 Bundle bundle = new Bundle();
4493 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
4494 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
4495 onResult(response, bundle);
4496 return;
4497 }
4498 // No qualified account exists, return an empty Bundle.
4499 onResult(response, new Bundle());
4500 }
4501
4502 @Override
4503 public void getAccountByTypeAndFeatures(
4504 IAccountManagerResponse response,
4505 String accountType,
4506 String[] features,
4507 String opPackageName) {
4508
4509 int callingUid = Binder.getCallingUid();
4510 mAppOpsManager.checkPackage(callingUid, opPackageName);
4511 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4512 Log.v(TAG, "getAccount: accountType " + accountType
4513 + ", response " + response
4514 + ", features " + Arrays.toString(features)
4515 + ", caller's uid " + callingUid
4516 + ", pid " + Binder.getCallingPid());
4517 }
4518 if (response == null) throw new IllegalArgumentException("response is null");
4519 if (accountType == null) throw new IllegalArgumentException("accountType is null");
4520
4521 int userId = UserHandle.getCallingUserId();
4522
4523 long identityToken = clearCallingIdentity();
4524 try {
4525 UserAccounts userAccounts = getUserAccounts(userId);
4526 if (ArrayUtils.isEmpty(features)) {
4527 Account[] accountsWithManagedNotVisible = getAccountsFromCache(
4528 userAccounts, accountType, callingUid, opPackageName,
4529 true /* include managed not visible */);
4530 handleGetAccountsResult(
4531 response, accountsWithManagedNotVisible, opPackageName);
4532 return;
4533 }
4534
4535 IAccountManagerResponse retrieveAccountsResponse =
4536 new IAccountManagerResponse.Stub() {
4537 @Override
4538 public void onResult(Bundle value) throws RemoteException {
4539 Parcelable[] parcelables = value.getParcelableArray(
4540 AccountManager.KEY_ACCOUNTS);
4541 Account[] accounts = new Account[parcelables.length];
4542 for (int i = 0; i < parcelables.length; i++) {
4543 accounts[i] = (Account) parcelables[i];
4544 }
4545 handleGetAccountsResult(
4546 response, accounts, opPackageName);
4547 }
4548
4549 @Override
4550 public void onError(int errorCode, String errorMessage)
4551 throws RemoteException {
4552 // Will not be called in this case.
4553 }
4554 };
4555 new GetAccountsByTypeAndFeatureSession(
4556 userAccounts,
4557 retrieveAccountsResponse,
4558 accountType,
4559 features,
4560 callingUid,
4561 opPackageName,
4562 true /* include managed not visible */).bind();
4563 } finally {
4564 restoreCallingIdentity(identityToken);
4565 }
4566 }
4567
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004568 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004569 public void getAccountsByFeatures(
4570 IAccountManagerResponse response,
4571 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004572 String[] features,
4573 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004574 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004575 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004576 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4577 Log.v(TAG, "getAccounts: accountType " + type
4578 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004579 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004580 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004581 + ", pid " + Binder.getCallingPid());
4582 }
Fred Quintana382601f2010-03-25 12:25:10 -07004583 if (response == null) throw new IllegalArgumentException("response is null");
4584 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004585 int userId = UserHandle.getCallingUserId();
4586
Svetoslavf3f02ac2015-09-08 14:36:35 -07004587 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4588 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004589 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004590 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004591 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004592 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004593 try {
4594 response.onResult(result);
4595 } catch (RemoteException e) {
4596 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4597 }
4598 return;
4599 }
sunjianf29d5492017-05-11 15:42:31 -07004600
Fred Quintana33269202009-04-20 16:05:10 -07004601 long identityToken = clearCallingIdentity();
4602 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004603 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004604 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004605 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4606 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004607 Bundle result = new Bundle();
4608 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4609 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004610 return;
4611 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004612 new GetAccountsByTypeAndFeatureSession(
4613 userAccounts,
4614 response,
4615 type,
4616 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004617 callingUid,
sunjianf29d5492017-05-11 15:42:31 -07004618 opPackageName,
4619 false /* include managed not visible */).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004620 } finally {
4621 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004622 }
4623 }
4624
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004625 @Override
4626 public void onAccountAccessed(String token) throws RemoteException {
4627 final int uid = Binder.getCallingUid();
4628 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4629 return;
4630 }
4631 final int userId = UserHandle.getCallingUserId();
4632 final long identity = Binder.clearCallingIdentity();
4633 try {
4634 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4635 if (Objects.equals(account.getAccessId(), token)) {
4636 // An app just accessed the account. At this point it knows about
4637 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004638 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004639 if (!hasAccountAccess(account, null, uid)) {
4640 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4641 uid, true);
4642 }
4643 }
4644 }
4645 } finally {
4646 Binder.restoreCallingIdentity(identity);
4647 }
4648 }
4649
Fred Quintanaa698f422009-04-08 19:14:54 -07004650 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004651 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004652 IAccountManagerResponse mResponse;
4653 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004654 final boolean mExpectActivityLaunch;
4655 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004656 final String mAccountName;
4657 // Indicates if we need to add auth details(like last credential time)
4658 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004659 // If set, we need to update the last authenticated time. This is
4660 // currently
4661 // used on
4662 // successful confirming credentials.
4663 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004664
Fred Quintana33269202009-04-20 16:05:10 -07004665 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004666 private int mNumRequestContinued = 0;
4667 private int mNumErrors = 0;
4668
Fred Quintana60307342009-03-24 22:48:12 -07004669 IAccountAuthenticator mAuthenticator = null;
4670
Fred Quintana8570f742010-02-18 10:32:54 -08004671 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004672 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004673
Amith Yamasani04e0d262012-02-14 11:50:53 -08004674 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004675 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4676 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004677 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4678 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4679 }
4680
4681 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4682 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4683 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004684 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004685 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004686 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004687 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004688 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004689 mResponse = response;
4690 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004691 mExpectActivityLaunch = expectActivityLaunch;
4692 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004693 mAccountName = accountName;
4694 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004695 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004696
Fred Quintanaa698f422009-04-08 19:14:54 -07004697 synchronized (mSessions) {
4698 mSessions.put(toString(), this);
4699 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004700 if (response != null) {
4701 try {
4702 response.asBinder().linkToDeath(this, 0 /* flags */);
4703 } catch (RemoteException e) {
4704 mResponse = null;
4705 binderDied();
4706 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004707 }
Fred Quintana60307342009-03-24 22:48:12 -07004708 }
4709
Fred Quintanaa698f422009-04-08 19:14:54 -07004710 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004711 if (mResponse == null) {
4712 // this session has already been closed
4713 return null;
4714 }
Fred Quintana60307342009-03-24 22:48:12 -07004715 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004716 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004717 return response;
4718 }
4719
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004720 /**
4721 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4722 * security policy.
4723 *
4724 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004725 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004726 * supplied entries in the system Settings app.
4727 */
tiansiminga8868bf2017-09-20 13:59:13 +08004728 protected boolean checkKeyIntent(int authUid, Intent intent) {
Jeff Sharkeyd722e782017-06-12 17:33:07 -06004729 intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
4730 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
4731 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4732 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004733 long bid = Binder.clearCallingIdentity();
4734 try {
4735 PackageManager pm = mContext.getPackageManager();
4736 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
tiansiminga8868bf2017-09-20 13:59:13 +08004737 if (resolveInfo == null) {
4738 return false;
4739 }
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004740 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4741 int targetUid = targetActivityInfo.applicationInfo.uid;
Dan Cashman303c4bb2018-04-10 07:41:16 -07004742 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004743 if (!isExportedSystemActivity(targetActivityInfo)
Dan Cashman303c4bb2018-04-10 07:41:16 -07004744 && !pmi.hasSignatureCapability(
4745 targetUid, authUid,
4746 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004747 String pkgName = targetActivityInfo.packageName;
4748 String activityName = targetActivityInfo.name;
4749 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4750 + "does not share a signature with the supplying authenticator (%s).";
tiansiminga8868bf2017-09-20 13:59:13 +08004751 Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
4752 return false;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004753 }
tiansiminga8868bf2017-09-20 13:59:13 +08004754 return true;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004755 } finally {
4756 Binder.restoreCallingIdentity(bid);
4757 }
4758 }
4759
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004760 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4761 String className = activityInfo.name;
4762 return "android".equals(activityInfo.packageName) &&
4763 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4764 || CantAddAccountActivity.class.getName().equals(className));
4765 }
4766
Fred Quintanaa698f422009-04-08 19:14:54 -07004767 private void close() {
4768 synchronized (mSessions) {
4769 if (mSessions.remove(toString()) == null) {
4770 // the session was already closed, so bail out now
4771 return;
4772 }
4773 }
4774 if (mResponse != null) {
4775 // stop listening for response deaths
4776 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4777
4778 // clear this so that we don't accidentally send any further results
4779 mResponse = null;
4780 }
4781 cancelTimeout();
4782 unbind();
4783 }
4784
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004785 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004786 public void binderDied() {
4787 mResponse = null;
4788 close();
4789 }
4790
4791 protected String toDebugString() {
4792 return toDebugString(SystemClock.elapsedRealtime());
4793 }
4794
4795 protected String toDebugString(long now) {
4796 return "Session: expectLaunch " + mExpectActivityLaunch
4797 + ", connected " + (mAuthenticator != null)
4798 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4799 + "/" + mNumErrors + ")"
4800 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4801 }
4802
Fred Quintana60307342009-03-24 22:48:12 -07004803 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004804 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4805 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4806 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004807 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004808 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004809 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004810 }
4811 }
4812
4813 private void unbind() {
4814 if (mAuthenticator != null) {
4815 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004816 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004817 }
4818 }
4819
Fred Quintana60307342009-03-24 22:48:12 -07004820 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004821 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004822 }
4823
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004824 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004825 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004826 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004827 try {
4828 run();
4829 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004830 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004831 "remote exception");
4832 }
Fred Quintana60307342009-03-24 22:48:12 -07004833 }
4834
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004835 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004836 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004837 mAuthenticator = null;
4838 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004839 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004840 try {
4841 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4842 "disconnected");
4843 } catch (RemoteException e) {
4844 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4845 Log.v(TAG, "Session.onServiceDisconnected: "
4846 + "caught RemoteException while responding", e);
4847 }
4848 }
Fred Quintana60307342009-03-24 22:48:12 -07004849 }
4850 }
4851
Fred Quintanab839afc2009-10-14 15:57:28 -07004852 public abstract void run() throws RemoteException;
4853
Fred Quintana60307342009-03-24 22:48:12 -07004854 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004855 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004856 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004857 try {
4858 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4859 "timeout");
4860 } catch (RemoteException e) {
4861 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4862 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4863 e);
4864 }
4865 }
Fred Quintana60307342009-03-24 22:48:12 -07004866 }
4867 }
4868
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004869 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004870 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004871 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004872 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004873 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004874 if (result != null) {
4875 boolean isSuccessfulConfirmCreds = result.getBoolean(
4876 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004877 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004878 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4879 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004880 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004881 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4882 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004883 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004884 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004885 if (needUpdate || mAuthDetailsRequired) {
4886 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4887 if (needUpdate && accountPresent) {
4888 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4889 }
4890 if (mAuthDetailsRequired) {
4891 long lastAuthenticatedTime = -1;
4892 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004893 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004894 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004895 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004896 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004897 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004898 lastAuthenticatedTime);
4899 }
4900 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004901 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004902 if (result != null
4903 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
tiansiminga8868bf2017-09-20 13:59:13 +08004904 if (!checkKeyIntent(
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004905 Binder.getCallingUid(),
tiansiminga8868bf2017-09-20 13:59:13 +08004906 intent)) {
4907 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
4908 "invalid intent in bundle returned");
4909 return;
4910 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004911 }
4912 if (result != null
4913 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004914 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4915 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004916 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4917 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004918 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4919 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004920 }
Fred Quintana60307342009-03-24 22:48:12 -07004921 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004922 IAccountManagerResponse response;
4923 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004924 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004925 response = mResponse;
4926 } else {
4927 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004928 }
Fred Quintana60307342009-03-24 22:48:12 -07004929 if (response != null) {
4930 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004931 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004932 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4933 Log.v(TAG, getClass().getSimpleName()
4934 + " calling onError() on response " + response);
4935 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004936 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004937 "null bundle returned");
4938 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004939 if (mStripAuthTokenFromResult) {
4940 result.remove(AccountManager.KEY_AUTHTOKEN);
4941 }
Fred Quintana56285a62010-12-02 14:20:51 -08004942 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4943 Log.v(TAG, getClass().getSimpleName()
4944 + " calling onResult() on response " + response);
4945 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004946 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4947 (intent == null)) {
4948 // All AccountManager error codes are greater than 0
4949 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4950 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4951 } else {
4952 response.onResult(result);
4953 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004954 }
Fred Quintana60307342009-03-24 22:48:12 -07004955 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004956 // if the caller is dead then there is no one to care about remote exceptions
4957 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4958 Log.v(TAG, "failure while notifying response", e);
4959 }
Fred Quintana60307342009-03-24 22:48:12 -07004960 }
4961 }
4962 }
Fred Quintana60307342009-03-24 22:48:12 -07004963
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004964 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004965 public void onRequestContinued() {
4966 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004967 }
4968
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004969 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004970 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004971 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004972 IAccountManagerResponse response = getResponseAndClose();
4973 if (response != null) {
4974 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004975 Log.v(TAG, getClass().getSimpleName()
4976 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004977 }
4978 try {
4979 response.onError(errorCode, errorMessage);
4980 } catch (RemoteException e) {
4981 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4982 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4983 }
4984 }
4985 } else {
4986 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4987 Log.v(TAG, "Session.onError: already closed");
4988 }
Fred Quintana60307342009-03-24 22:48:12 -07004989 }
4990 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004991
4992 /**
4993 * find the component name for the authenticator and initiate a bind
4994 * if no authenticator or the bind fails then return false, otherwise return true
4995 */
4996 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004997 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4998 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4999 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07005000 if (authenticatorInfo == null) {
5001 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5002 Log.v(TAG, "there is no authenticator for " + authenticatorType
5003 + ", bailing out");
5004 }
5005 return false;
5006 }
5007
Jeff Sharkeyce18c812016-04-27 16:00:41 -06005008 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06005009 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07005010 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
5011 + " which isn't encryption aware");
5012 return false;
5013 }
5014
Fred Quintanab839afc2009-10-14 15:57:28 -07005015 Intent intent = new Intent();
5016 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
5017 intent.setComponent(authenticatorInfo.componentName);
5018 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5019 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
5020 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08005021 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005022 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07005023 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5024 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
5025 }
5026 return false;
5027 }
5028
Fred Quintanab839afc2009-10-14 15:57:28 -07005029 return true;
5030 }
Fred Quintana60307342009-03-24 22:48:12 -07005031 }
5032
Svet Ganov5d09c992016-09-07 09:57:41 -07005033 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07005034 MessageHandler(Looper looper) {
5035 super(looper);
5036 }
Costin Manolache3348f142009-09-29 18:58:36 -07005037
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07005038 @Override
Fred Quintana60307342009-03-24 22:48:12 -07005039 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07005040 switch (msg.what) {
5041 case MESSAGE_TIMED_OUT:
5042 Session session = (Session)msg.obj;
5043 session.onTimedOut();
5044 break;
5045
Amith Yamasani5be347b2013-03-31 17:44:31 -07005046 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00005047 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07005048 break;
5049
Fred Quintana60307342009-03-24 22:48:12 -07005050 default:
5051 throw new IllegalStateException("unhandled message: " + msg.what);
5052 }
5053 }
5054 }
5055
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005056 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005057 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005058 }
5059
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005060 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005061 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07005062 }
5063
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005064 /*
5065 * This function receives an opened writable database.
5066 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005067 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005068 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005069 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005070 }
5071
5072 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005073 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005074 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005075 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005076 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005077
5078 class LogRecordTask implements Runnable {
5079 private final String action;
5080 private final String tableName;
5081 private final long accountId;
5082 private final UserAccounts userAccount;
5083 private final int callingUid;
5084 private final long userDebugDbInsertionPoint;
5085
5086 LogRecordTask(final String action,
5087 final String tableName,
5088 final long accountId,
5089 final UserAccounts userAccount,
5090 final int callingUid,
5091 final long userDebugDbInsertionPoint) {
5092 this.action = action;
5093 this.tableName = tableName;
5094 this.accountId = accountId;
5095 this.userAccount = userAccount;
5096 this.callingUid = callingUid;
5097 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
5098 }
5099
Andrew Scullc7770d62017-05-22 17:49:58 +01005100 @Override
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005101 public void run() {
5102 SQLiteStatement logStatement = userAccount.statementForLogging;
5103 logStatement.bindLong(1, accountId);
5104 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005105 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005106 logStatement.bindLong(4, callingUid);
5107 logStatement.bindString(5, tableName);
5108 logStatement.bindLong(6, userDebugDbInsertionPoint);
Tetsutoki Shiozawabe2d96a2017-10-24 18:44:00 +09005109 try {
5110 logStatement.execute();
5111 } catch (IllegalStateException e) {
5112 // Guard against crash, DB can already be closed
5113 // since this statement is executed on a handler thread
5114 Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
5115 + " action=" + action + " tableName=" + tableName + " Error: " + e);
5116 } finally {
5117 logStatement.clearBindings();
5118 }
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07005119 }
5120 }
5121
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005122 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
5123 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005124 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005125 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07005126 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07005127 }
5128
5129 /*
5130 * This should only be called once to compile the sql statement for logging
5131 * and to find the insertion point.
5132 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005133 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
5134 userAccount.debugDbInsertionPoint = userAccount.accountsDb
5135 .calculateDebugTableInsertionPoint();
5136 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005137 }
5138
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005139 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07005140 return asBinder();
5141 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005142
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005143 /**
5144 * Searches array of arguments for the specified string
5145 * @param args array of argument strings
5146 * @param value value to search for
5147 * @return true if the value is contained in the array
5148 */
5149 private static boolean scanArgs(String[] args, String value) {
5150 if (args != null) {
5151 for (String arg : args) {
5152 if (value.equals(arg)) {
5153 return true;
5154 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005155 }
5156 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005157 return false;
5158 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005159
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005160 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005161 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005162 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005163 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005164 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07005165
Jeff Sharkey6eb96202012-10-10 13:13:54 -07005166 final List<UserInfo> users = getUserManager().getUsers();
5167 for (UserInfo user : users) {
5168 ipw.println("User " + user + ":");
5169 ipw.increaseIndent();
5170 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
5171 ipw.println();
5172 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08005173 }
5174 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005175
Amith Yamasani04e0d262012-02-14 11:50:53 -08005176 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
5177 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005178 if (isCheckinRequest) {
5179 // This is a checkin request. *Only* upload the account types and the count of
5180 // each.
5181 synchronized (userAccounts.dbLock) {
5182 userAccounts.accountsDb.dumpDeAccountsTable(fout);
5183 }
5184 } else {
5185 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
5186 Process.SYSTEM_UID, null /* packageName */, false);
5187 fout.println("Accounts: " + accounts.length);
5188 for (Account account : accounts) {
5189 fout.println(" " + account);
5190 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005191
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005192 // Add debug information.
5193 fout.println();
5194 synchronized (userAccounts.dbLock) {
5195 userAccounts.accountsDb.dumpDebugTable(fout);
5196 }
5197 fout.println();
5198 synchronized (mSessions) {
5199 final long now = SystemClock.elapsedRealtime();
5200 fout.println("Active Sessions: " + mSessions.size());
5201 for (Session session : mSessions.values()) {
5202 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005203 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005204 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005205
5206 fout.println();
5207 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Tony Mak6d14d772017-07-13 17:49:46 +08005208
5209 boolean isUserUnlocked;
5210 synchronized (mUsers) {
5211 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
5212 }
5213 // Following logs are printed only when user is unlocked.
5214 if (!isUserUnlocked) {
5215 return;
5216 }
5217 fout.println();
5218 synchronized (userAccounts.dbLock) {
5219 Map<Account, Map<String, Integer>> allVisibilityValues =
5220 userAccounts.accountsDb.findAllVisibilityValues();
5221 fout.println("Account visibility:");
5222 for (Account account : allVisibilityValues.keySet()) {
5223 fout.println(" " + account.name);
5224 Map<String, Integer> visibilities = allVisibilityValues.get(account);
5225 for (Entry<String, Integer> entry : visibilities.entrySet()) {
5226 fout.println(" " + entry.getKey() + ", " + entry.getValue());
5227 }
5228 }
5229 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07005230 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005231 }
5232
Amith Yamasani04e0d262012-02-14 11:50:53 -08005233 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005234 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005235 long identityToken = clearCallingIdentity();
5236 try {
5237 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5238 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
5239 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005240
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005241 if (intent.getComponent() != null &&
5242 GrantCredentialsPermissionActivity.class.getName().equals(
5243 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005244 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005245 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005246 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04005247 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
5248 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005249
Fred Quintana33f889a2009-09-14 17:31:26 -07005250 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005251 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05005252 Notification n =
5253 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005254 .setWhen(0)
5255 .setSmallIcon(android.R.drawable.stat_sys_warning)
5256 .setColor(contextForUser.getColor(
5257 com.android.internal.R.color.system_notification_accent_color))
5258 .setContentTitle(String.format(notificationTitleFormat, account.name))
5259 .setContentText(message)
5260 .setContentIntent(PendingIntent.getActivityAsUser(
5261 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005262 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04005263 .build();
Chris Wren717a8812017-03-31 15:34:39 -04005264 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005265 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005266 } finally {
5267 restoreCallingIdentity(identityToken);
5268 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005269 }
5270
Chris Wren717a8812017-03-31 15:34:39 -04005271 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005272 String packageName, int userId) {
5273 final long token = clearCallingIdentity();
5274 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005275 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005276 try {
Chris Wren717a8812017-03-31 15:34:39 -04005277 notificationManager.enqueueNotificationWithTag(packageName, packageName,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04005278 id.mTag, id.mId, notification, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005279 } catch (RemoteException e) {
5280 /* ignore - local call */
5281 }
5282 } finally {
5283 Binder.restoreCallingIdentity(token);
5284 }
Fred Quintana56285a62010-12-02 14:20:51 -08005285 }
5286
Chris Wren717a8812017-03-31 15:34:39 -04005287 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005288 cancelNotification(id, mContext.getPackageName(), user);
5289 }
5290
Chris Wren717a8812017-03-31 15:34:39 -04005291 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005292 long identityToken = clearCallingIdentity();
5293 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07005294 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04005295 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005296 } catch (RemoteException e) {
5297 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07005298 } finally {
5299 restoreCallingIdentity(identityToken);
5300 }
Fred Quintanaa698f422009-04-08 19:14:54 -07005301 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005302
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005303 private boolean isPermittedForPackage(String packageName, int uid, int userId,
5304 String... permissions) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005305 final long identity = Binder.clearCallingIdentity();
5306 try {
5307 IPackageManager pm = ActivityThread.getPackageManager();
5308 for (String perm : permissions) {
5309 if (pm.checkPermission(perm, packageName, userId)
5310 == PackageManager.PERMISSION_GRANTED) {
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005311 // Checks runtime permission revocation.
5312 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005313 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005314 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
5315 return true;
5316 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005317 }
5318 }
5319 } catch (RemoteException e) {
5320 /* ignore - local call */
5321 } finally {
5322 Binder.restoreCallingIdentity(identity);
5323 }
5324 return false;
5325 }
5326
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005327 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5328 for (String perm : permissions) {
5329 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5330 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5331 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5332 }
5333 final int opCode = AppOpsManager.permissionToOpCode(perm);
Tony Mak58f28152017-09-20 21:23:48 +01005334 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005335 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5336 return true;
5337 }
5338 }
5339 }
5340 return false;
5341 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005342
Amith Yamasani67df64b2012-12-14 12:09:36 -08005343 private int handleIncomingUser(int userId) {
5344 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005345 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005346 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5347 } catch (RemoteException re) {
5348 // Shouldn't happen, local.
5349 }
5350 return userId;
5351 }
5352
Christopher Tateccbf84f2013-05-08 15:25:41 -07005353 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005354 String[] packages;
5355 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005356 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005357 packages = mPackageManager.getPackagesForUid(callingUid);
sunjian9ae597b62017-08-14 15:45:04 -07005358 if (packages == null) {
5359 Log.d(TAG, "No packages for callingUid " + callingUid);
Fred Quintana7be59642009-08-24 18:29:25 -07005360 return false;
5361 }
sunjian9ae597b62017-08-14 15:45:04 -07005362 for (String name : packages) {
5363 try {
5364 PackageInfo packageInfo =
5365 mPackageManager.getPackageInfo(name, 0 /* flags */);
5366 if (packageInfo != null
5367 && (packageInfo.applicationInfo.privateFlags
5368 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
5369 return true;
5370 }
5371 } catch (PackageManager.NameNotFoundException e) {
5372 Log.d(TAG, "Package not found " + e.getMessage());
5373 }
5374 }
5375 } finally {
5376 Binder.restoreCallingIdentity(identityToken);
Fred Quintana7be59642009-08-24 18:29:25 -07005377 }
5378 return false;
5379 }
5380
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005381 private boolean permissionIsGranted(
5382 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005383 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5384 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5385 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5386 }
5387 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005388 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005389
5390 if (isPrivileged(callerUid)) {
5391 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5392 Log.v(TAG, "Access to " + account + " granted calling uid "
5393 + callerUid + " privileged");
5394 }
5395 return true;
5396 }
5397 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5398 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5399 Log.v(TAG, "Access to " + account + " granted calling uid "
5400 + callerUid + " manages the account");
5401 }
5402 return true;
5403 }
5404 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5405 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5406 Log.v(TAG, "Access to " + account + " granted calling uid "
5407 + callerUid + " user granted access");
5408 }
5409 return true;
5410 }
5411
5412 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5413 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5414 }
5415
5416 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005417 }
5418
Svetoslavf3f02ac2015-09-08 14:36:35 -07005419 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5420 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005421 if (accountType == null) {
5422 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005423 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005424 return getTypesVisibleToCaller(callingUid, userId,
5425 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005426 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005427 }
5428
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005429 // Method checks visibility for applications targeing API level below {@link
5430 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005431 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005432 private boolean checkGetAccountsPermission(String packageName, int uid, int userId) {
5433 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005434 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5435 }
5436
Dmitry Dementyevd6f06722017-04-05 12:43:26 -07005437 private boolean checkReadContactsPermission(String packageName, int uid, int userId) {
5438 return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS);
5439 }
5440
5441 // Heuristic to check that account type may be associated with some contacts data and
5442 // therefore READ_CONTACTS permission grants the access to account by default.
5443 private boolean accountTypeManagesContacts(String accountType, int userId) {
5444 if (accountType == null) {
5445 return false;
5446 }
5447 long identityToken = Binder.clearCallingIdentity();
5448 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5449 try {
5450 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5451 } finally {
5452 Binder.restoreCallingIdentity(identityToken);
5453 }
5454 // Check contacts related permissions for authenticator.
5455 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5456 : serviceInfos) {
5457 if (accountType.equals(serviceInfo.type.type)) {
5458 return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId,
5459 Manifest.permission.WRITE_CONTACTS);
5460 }
5461 }
5462 return false;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005463 }
5464
5465 /**
5466 * Method checks package uid and signature with Authenticator which manages accountType.
5467 *
5468 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5469 * SIGNATURE_CHECK_MISMATCH otherwise.
5470 */
5471 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5472 if (accountType == null) {
5473 return SIGNATURE_CHECK_MISMATCH;
5474 }
5475
5476 long identityToken = Binder.clearCallingIdentity();
5477 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5478 try {
5479 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5480 } finally {
5481 Binder.restoreCallingIdentity(identityToken);
5482 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005483 // Check for signature match with Authenticator.LocalServices.getService(PackageManagerInternal.class);
5484 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005485 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5486 : serviceInfos) {
5487 if (accountType.equals(serviceInfo.type.type)) {
5488 if (serviceInfo.uid == callingUid) {
5489 return SIGNATURE_CHECK_UID_MATCH;
5490 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005491 if (pmi.hasSignatureCapability(
5492 serviceInfo.uid, callingUid,
5493 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005494 return SIGNATURE_CHECK_MATCH;
5495 }
5496 }
5497 }
5498 return SIGNATURE_CHECK_MISMATCH;
5499 }
5500
5501 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005502 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5503 if (accountType == null) {
5504 return false;
5505 } else {
5506 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5507 }
5508 }
5509
Svetoslavf3f02ac2015-09-08 14:36:35 -07005510 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5511 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005512 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005513 }
5514
5515 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005516 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005517 }
5518
5519 private List<String> getTypesForCaller(
5520 int callingUid, int userId, boolean isOtherwisePermitted) {
5521 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005522 long identityToken = Binder.clearCallingIdentity();
5523 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5524 try {
5525 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5526 } finally {
5527 Binder.restoreCallingIdentity(identityToken);
5528 }
Dan Cashman303c4bb2018-04-10 07:41:16 -07005529
5530 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005531 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005532 serviceInfos) {
Dan Cashman303c4bb2018-04-10 07:41:16 -07005533 if (isOtherwisePermitted || pmi.hasSignatureCapability(
5534 serviceInfo.uid, callingUid,
5535 PackageParser.SigningDetails.CertCapabilities.AUTH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005536 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005537 }
5538 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005539 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005540 }
5541
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005542 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5543 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5544 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5545 if (account.name.equals(accountName)) {
5546 return true;
5547 }
5548 }
5549 }
5550 return false;
5551 }
5552
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005553 private static void checkManageUsersPermission(String message) {
5554 if (ActivityManager.checkComponentPermission(
5555 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5556 != PackageManager.PERMISSION_GRANTED) {
5557 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5558 }
5559 }
5560
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005561 private static void checkManageOrCreateUsersPermission(String message) {
5562 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5563 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5564 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5565 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5566 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5567 + message);
5568 }
5569 }
5570
Amith Yamasani04e0d262012-02-14 11:50:53 -08005571 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5572 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005573 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005574 return true;
5575 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005576 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005577 synchronized (accounts.dbLock) {
5578 synchronized (accounts.cacheLock) {
5579 long grantsCount;
5580 if (authTokenType != null) {
5581 grantsCount = accounts.accountsDb
5582 .findMatchingGrantsCount(callerUid, authTokenType, account);
5583 } else {
5584 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5585 account);
5586 }
5587 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005588
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005589 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5590 // TODO: Skip this check when running automated tests. Replace this
5591 // with a more general solution.
5592 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5593 + authTokenType + " by uid " + callerUid
5594 + " but ignoring since device is in test harness.");
5595 return true;
5596 }
5597 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005598 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005599 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005600 }
5601
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005602 private boolean isSystemUid(int callingUid) {
5603 String[] packages = null;
5604 long ident = Binder.clearCallingIdentity();
5605 try {
5606 packages = mPackageManager.getPackagesForUid(callingUid);
Alex Chau81a47cd2018-01-02 16:49:14 +00005607 if (packages != null) {
5608 for (String name : packages) {
5609 try {
5610 PackageInfo packageInfo =
5611 mPackageManager.getPackageInfo(name, 0 /* flags */);
5612 if (packageInfo != null
5613 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5614 != 0) {
5615 return true;
5616 }
5617 } catch (NameNotFoundException e) {
5618 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5619 }
5620 }
5621 } else {
5622 Log.w(TAG, "No known packages with uid " + callingUid);
5623 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005624 } finally {
5625 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005626 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005627 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005628 }
5629
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005630 /** Succeeds if any of the specified permissions are granted. */
5631 private void checkReadAccountsPermitted(
5632 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005633 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005634 int userId,
5635 String opPackageName) {
5636 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005637 String msg = String.format(
5638 "caller uid %s cannot access %s accounts",
5639 callingUid,
5640 accountType);
5641 Log.w(TAG, " " + msg);
5642 throw new SecurityException(msg);
5643 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005644 }
5645
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005646 private boolean canUserModifyAccounts(int userId, int callingUid) {
5647 // the managing app can always modify accounts
5648 if (isProfileOwner(callingUid)) {
5649 return true;
5650 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005651 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5652 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5653 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005654 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005655 return true;
5656 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005657
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005658 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5659 // the managing app can always modify accounts
5660 if (isProfileOwner(callingUid)) {
5661 return true;
5662 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005663 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5664 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005665 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005666 if (typesArray == null) {
5667 return true;
5668 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005669 for (String forbiddenType : typesArray) {
5670 if (forbiddenType.equals(accountType)) {
5671 return false;
5672 }
5673 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005674 return true;
5675 }
5676
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005677 private boolean isProfileOwner(int uid) {
5678 final DevicePolicyManagerInternal dpmi =
5679 LocalServices.getService(DevicePolicyManagerInternal.class);
5680 return (dpmi != null)
5681 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5682 }
5683
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005684 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005685 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5686 throws RemoteException {
5687 final int callingUid = getCallingUid();
5688
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005689 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005690 throw new SecurityException();
5691 }
5692
5693 if (value) {
5694 grantAppPermission(account, authTokenType, uid);
5695 } else {
5696 revokeAppPermission(account, authTokenType, uid);
5697 }
5698 }
5699
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005700 /**
5701 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5702 * <p>
5703 * Although this is public it can only be accessed via the AccountManagerService object
5704 * which is in the system. This means we don't need to protect it with permissions.
5705 * @hide
5706 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005707 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005708 if (account == null || authTokenType == null) {
5709 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005710 return;
5711 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005712 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005713 synchronized (accounts.dbLock) {
5714 synchronized (accounts.cacheLock) {
5715 long accountId = accounts.accountsDb.findDeAccountId(account);
5716 if (accountId >= 0) {
5717 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5718 }
5719 cancelNotification(
5720 getCredentialPermissionNotificationId(account, authTokenType, uid),
5721 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005722
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005723 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5724 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005725 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005726
5727 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5728 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5729 : mAppPermissionChangeListeners) {
5730 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5731 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005732 }
5733
5734 /**
5735 * Don't allow callers with the given uid permission to get credentials for
5736 * account/authTokenType.
5737 * <p>
5738 * Although this is public it can only be accessed via the AccountManagerService object
5739 * which is in the system. This means we don't need to protect it with permissions.
5740 * @hide
5741 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005742 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005743 if (account == null || authTokenType == null) {
5744 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005745 return;
5746 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005747 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005748 synchronized (accounts.dbLock) {
5749 synchronized (accounts.cacheLock) {
5750 accounts.accountsDb.beginTransaction();
5751 try {
5752 long accountId = accounts.accountsDb.findDeAccountId(account);
5753 if (accountId >= 0) {
5754 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5755 accountId, authTokenType, uid);
5756 accounts.accountsDb.setTransactionSuccessful();
5757 }
5758 } finally {
5759 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005760 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005761
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005762 cancelNotification(
5763 getCredentialPermissionNotificationId(account, authTokenType, uid),
5764 UserHandle.of(accounts.userId));
5765 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005766 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005767
5768 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5769 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5770 : mAppPermissionChangeListeners) {
5771 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5772 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005773 }
Fred Quintana56285a62010-12-02 14:20:51 -08005774
Amith Yamasani04e0d262012-02-14 11:50:53 -08005775 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5776 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005777 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005778 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005779 for (Account curAccount : oldAccountsForType) {
5780 if (!curAccount.equals(account)) {
5781 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005782 }
5783 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005784 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005785 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005786 } else {
5787 Account[] newAccountsForType = new Account[newAccountsList.size()];
5788 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005789 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005790 }
Fred Quintana56285a62010-12-02 14:20:51 -08005791 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005792 accounts.userDataCache.remove(account);
5793 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005794 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005795 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005796 }
5797
5798 /**
5799 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005800 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5801 * processes and if you will return this account to apps you should return the result.
5802 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005803 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005804 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005805 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005806 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5807 Account[] newAccountsForType = new Account[oldLength + 1];
5808 if (accountsForType != null) {
5809 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005810 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005811 String token = account.getAccessId() != null ? account.getAccessId()
5812 : UUID.randomUUID().toString();
5813 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005814 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005815 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005816 }
5817
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005818 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005819 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005820 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005821 String visibilityFilterPackage = callingPackage;
5822 if (visibilityFilterPackage == null) {
5823 visibilityFilterPackage = getPackageNameForUid(callingUid);
5824 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005825 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005826 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005827 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005828 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5829 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5830 || (includeManagedNotVisible
5831 && (visibility
5832 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5833 firstPass.put(account, visibility);
5834 }
5835 }
5836 Map<Account, Integer> secondPass =
5837 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5838
5839 Account[] filtered = new Account[secondPass.size()];
5840 filtered = secondPass.keySet().toArray(filtered);
5841 return filtered;
5842 }
5843
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005844 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005845 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005846 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005847 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005848 // first part is to filter shared accounts.
5849 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005850 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005851 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005852 return unfiltered;
5853 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005854 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005855 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005856 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005857 if (packages == null) {
5858 packages = new String[] {};
5859 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005860 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005861 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005862 // This might be a temporary way to specify a visible list
5863 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005864 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5865 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005866 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005867 return unfiltered;
5868 }
5869 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005870 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005871 if (ArrayUtils.isEmpty(sharedAccounts)) {
5872 return unfiltered;
5873 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005874 String requiredAccountType = "";
5875 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005876 // If there's an explicit callingPackage specified, check if that package
5877 // opted in to see restricted accounts.
5878 if (callingPackage != null) {
5879 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005880 if (pi != null && pi.restrictedAccountType != null) {
5881 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005882 }
5883 } else {
5884 // Otherwise check if the callingUid has a package that has opted in
5885 for (String packageName : packages) {
5886 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5887 if (pi != null && pi.restrictedAccountType != null) {
5888 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005889 break;
5890 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005891 }
5892 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005893 } catch (NameNotFoundException e) {
5894 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005895 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005896 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005897 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5898 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005899 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005900 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005901 } else {
5902 boolean found = false;
5903 for (Account shared : sharedAccounts) {
5904 if (shared.equals(account)) {
5905 found = true;
5906 break;
5907 }
5908 }
5909 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005910 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005911 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005912 }
5913 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005914 return filtered;
5915 } else {
5916 return unfiltered;
5917 }
5918 }
5919
Amith Yamasani27db4682013-03-30 17:07:47 -07005920 /*
5921 * packageName can be null. If not null, it should be used to filter out restricted accounts
5922 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005923 *
5924 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5925 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005926 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005927 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005928 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005929 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005930 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5931 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005932 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005933 Account[] accounts;
5934 synchronized (userAccounts.cacheLock) {
5935 accounts = userAccounts.accountCache.get(accountType);
5936 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005937 if (accounts == null) {
5938 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005939 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005940 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5941 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005942 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005943 } else {
5944 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005945 Account[] accountsArray;
5946 synchronized (userAccounts.cacheLock) {
5947 for (Account[] accounts : userAccounts.accountCache.values()) {
5948 totalLength += accounts.length;
5949 }
5950 if (totalLength == 0) {
5951 return EMPTY_ACCOUNT_ARRAY;
5952 }
5953 accountsArray = new Account[totalLength];
5954 totalLength = 0;
5955 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5956 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5957 accountsOfType.length);
5958 totalLength += accountsOfType.length;
5959 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005960 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005961 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005962 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005963 }
5964 }
5965
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005966 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005967 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005968 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005969 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005970 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005971 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005972 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005973 }
5974 if (value == null) {
5975 userDataForAccount.remove(key);
5976 } else {
5977 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005978 }
5979 }
5980
Carlos Valdivia91979be2015-05-22 14:11:35 -07005981 protected String readCachedTokenInternal(
5982 UserAccounts accounts,
5983 Account account,
5984 String tokenType,
5985 String callingPackage,
5986 byte[] pkgSigDigest) {
Dmitry Dementyev18f0ca92017-06-12 17:56:47 -07005987 synchronized (accounts.cacheLock) {
5988 return accounts.accountTokenCaches.get(
5989 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07005990 }
5991 }
5992
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005993 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005994 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005995 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005996 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005997 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005998 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005999 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08006000 }
6001 if (value == null) {
6002 authTokensForAccount.remove(key);
6003 } else {
6004 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08006005 }
6006 }
6007
Amith Yamasani04e0d262012-02-14 11:50:53 -08006008 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
6009 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07006010 // Fast path - check if account is already cached
6011 synchronized (accounts.cacheLock) {
6012 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6013 if (authTokensForAccount != null) {
6014 return authTokensForAccount.get(authTokenType);
6015 }
6016 }
6017 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07006018 synchronized (accounts.dbLock) {
6019 synchronized (accounts.cacheLock) {
6020 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
6021 if (authTokensForAccount == null) {
6022 // need to populate the cache for this account
6023 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
6024 accounts.authTokenCache.put(account, authTokensForAccount);
6025 }
6026 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08006027 }
Fred Quintana56285a62010-12-02 14:20:51 -08006028 }
6029 }
6030
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006031 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
6032 Map<String, String> userDataForAccount;
6033 // Fast path - check if data is already cached
6034 synchronized (accounts.cacheLock) {
6035 userDataForAccount = accounts.userDataCache.get(account);
6036 }
6037 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00006038 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07006039 synchronized (accounts.dbLock) {
6040 synchronized (accounts.cacheLock) {
6041 userDataForAccount = accounts.userDataCache.get(account);
6042 if (userDataForAccount == null) {
6043 // need to populate the cache for this account
6044 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
6045 accounts.userDataCache.put(account, userDataForAccount);
6046 }
6047 }
6048 }
Fred Quintana56285a62010-12-02 14:20:51 -08006049 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00006050 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08006051 }
6052
Kenny Guy07ad8dc2014-09-01 20:56:12 +01006053 private Context getContextForUser(UserHandle user) {
6054 try {
6055 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
6056 } catch (NameNotFoundException e) {
6057 // Default to mContext, not finding the package system is running as is unlikely.
6058 return mContext;
6059 }
6060 }
Sandra Kwan78812282015-11-04 11:19:47 -08006061
6062 private void sendResponse(IAccountManagerResponse response, Bundle result) {
6063 try {
6064 response.onResult(result);
6065 } catch (RemoteException e) {
6066 // if the caller is dead then there is no one to care about remote
6067 // exceptions
6068 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6069 Log.v(TAG, "failure while notifying response", e);
6070 }
6071 }
6072 }
6073
6074 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
6075 String errorMessage) {
6076 try {
6077 response.onError(errorCode, errorMessage);
6078 } catch (RemoteException e) {
6079 // if the caller is dead then there is no one to care about remote
6080 // exceptions
6081 if (Log.isLoggable(TAG, Log.VERBOSE)) {
6082 Log.v(TAG, "failure while notifying response", e);
6083 }
6084 }
6085 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006086
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006087 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07006088 private final Object mLock = new Object();
6089
6090 @GuardedBy("mLock")
6091 private AccountManagerBackupHelper mBackupHelper;
6092
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006093 @Override
6094 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
6095 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
6096 if (account == null) {
6097 Slog.w(TAG, "account cannot be null");
6098 return;
6099 }
6100 if (packageName == null) {
6101 Slog.w(TAG, "packageName cannot be null");
6102 return;
6103 }
6104 if (userId < UserHandle.USER_SYSTEM) {
6105 Slog.w(TAG, "user id must be concrete");
6106 return;
6107 }
6108 if (callback == null) {
6109 Slog.w(TAG, "callback cannot be null");
6110 return;
6111 }
6112
Dmitry Dementyev7b3ea132017-05-10 12:45:02 -07006113 int visibility =
6114 resolveAccountVisibility(account, packageName, getUserAccounts(userId));
6115 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
6116 Slog.w(TAG, "requestAccountAccess: account is hidden");
6117 return;
6118 }
6119
Svet Ganovf6d424f12016-09-20 20:18:53 -07006120 if (AccountManagerService.this.hasAccountAccess(account, packageName,
6121 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006122 Bundle result = new Bundle();
6123 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
6124 callback.sendResult(result);
6125 return;
6126 }
6127
6128 final int uid;
6129 try {
6130 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
6131 } catch (NameNotFoundException e) {
6132 Slog.e(TAG, "Unknown package " + packageName);
6133 return;
6134 }
6135
6136 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006137 final UserAccounts userAccounts;
6138 synchronized (mUsers) {
6139 userAccounts = mUsers.get(userId);
6140 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04006141 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07006142 doNotification(userAccounts, account, null, intent, packageName, userId);
6143 }
6144
6145 @Override
6146 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
6147 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
6148 mAppPermissionChangeListeners.add(listener);
6149 }
6150
6151 @Override
6152 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
6153 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07006154 }
Svet Ganov5d09c992016-09-07 09:57:41 -07006155
6156 @Override
6157 public byte[] backupAccountAccessPermissions(int userId) {
6158 synchronized (mLock) {
6159 if (mBackupHelper == null) {
6160 mBackupHelper = new AccountManagerBackupHelper(
6161 AccountManagerService.this, this);
6162 }
6163 return mBackupHelper.backupAccountAccessPermissions(userId);
6164 }
6165 }
6166
6167 @Override
6168 public void restoreAccountAccessPermissions(byte[] data, int userId) {
6169 synchronized (mLock) {
6170 if (mBackupHelper == null) {
6171 mBackupHelper = new AccountManagerBackupHelper(
6172 AccountManagerService.this, this);
6173 }
6174 mBackupHelper.restoreAccountAccessPermissions(data, userId);
6175 }
6176 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07006177 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07006178
6179 @VisibleForTesting
6180 static class Injector {
6181 private final Context mContext;
6182
6183 public Injector(Context context) {
6184 mContext = context;
6185 }
6186
6187 Looper getMessageHandlerLooper() {
6188 ServiceThread serviceThread = new ServiceThread(TAG,
6189 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
6190 serviceThread.start();
6191 return serviceThread.getLooper();
6192 }
6193
6194 Context getContext() {
6195 return mContext;
6196 }
6197
6198 void addLocalService(AccountManagerInternal service) {
6199 LocalServices.addService(AccountManagerInternal.class, service);
6200 }
6201
6202 String getDeDatabaseName(int userId) {
6203 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
6204 AccountsDb.DE_DATABASE_NAME);
6205 return databaseFile.getPath();
6206 }
6207
6208 String getCeDatabaseName(int userId) {
6209 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
6210 AccountsDb.CE_DATABASE_NAME);
6211 return databaseFile.getPath();
6212 }
6213
6214 String getPreNDatabaseName(int userId) {
6215 File systemDir = Environment.getDataSystemDirectory();
6216 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
6217 PRE_N_DATABASE_NAME);
6218 if (userId == 0) {
6219 // Migrate old file, if it exists, to the new location.
6220 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006221 // accidentally created in the old location,
6222 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07006223 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
6224 if (oldFile.exists() && !databaseFile.exists()) {
6225 // Check for use directory; create if it doesn't exist, else renameTo will fail
6226 File userDir = Environment.getUserSystemDirectory(userId);
6227 if (!userDir.exists()) {
6228 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006229 throw new IllegalStateException(
6230 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006231 }
6232 }
6233 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08006234 throw new IllegalStateException(
6235 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07006236 }
6237 }
6238 }
6239 return databaseFile.getPath();
6240 }
6241
6242 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
6243 return new AccountAuthenticatorCache(mContext);
6244 }
6245
6246 INotificationManager getNotificationManager() {
6247 return NotificationManager.getService();
6248 }
6249 }
Chris Wren717a8812017-03-31 15:34:39 -04006250
Andrew Scullc7770d62017-05-22 17:49:58 +01006251 private static class NotificationId {
Chris Wren717a8812017-03-31 15:34:39 -04006252 final String mTag;
6253 private final int mId;
6254
6255 NotificationId(String tag, int type) {
6256 mTag = tag;
6257 mId = type;
6258 }
6259 }
Fred Quintana60307342009-03-24 22:48:12 -07006260}