blob: e560d325e6ddaf752849a858dcdd07572989e089 [file] [log] [blame]
Fred Quintana60307342009-03-24 22:48:12 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.accounts;
Fred Quintana60307342009-03-24 22:48:12 -070018
Doug Zongker885cfc232009-10-21 16:52:44 -070019import android.Manifest;
Carlos Valdivia91979be2015-05-22 14:11:35 -070020import android.accounts.AbstractAccountAuthenticator;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080021import android.accounts.Account;
22import android.accounts.AccountAndUser;
23import android.accounts.AccountAuthenticatorResponse;
24import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070025import android.accounts.AccountManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080026import android.accounts.AuthenticatorDescription;
Amith Yamasani23c8b962013-04-10 13:37:18 -070027import android.accounts.CantAddAccountActivity;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080028import android.accounts.GrantCredentialsPermissionActivity;
29import android.accounts.IAccountAuthenticator;
30import android.accounts.IAccountAuthenticatorResponse;
31import android.accounts.IAccountManager;
32import android.accounts.IAccountManagerResponse;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070033import android.annotation.IntRange;
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070034import android.annotation.NonNull;
Svet Ganovf6d424f12016-09-20 20:18:53 -070035import android.annotation.Nullable;
Brett Chabot3b4fcbc2011-01-09 13:41:02 -080036import android.app.ActivityManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070037import android.app.ActivityThread;
Svetoslavf3f02ac2015-09-08 14:36:35 -070038import android.app.AppOpsManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070039import android.app.INotificationManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070040import android.app.Notification;
41import android.app.NotificationManager;
42import android.app.PendingIntent;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000043import android.app.admin.DeviceAdminInfo;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010044import android.app.admin.DevicePolicyManager;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000045import android.app.admin.DevicePolicyManagerInternal;
Fred Quintanaa698f422009-04-08 19:14:54 -070046import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070047import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070048import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070051import android.content.IntentSender;
Fred Quintanab839afc2009-10-14 15:57:28 -070052import android.content.ServiceConnection;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -080053import android.content.pm.ActivityInfo;
Doug Zongker885cfc232009-10-21 16:52:44 -070054import android.content.pm.ApplicationInfo;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070055import android.content.pm.IPackageManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070056import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070057import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070058import android.content.pm.PackageManager.NameNotFoundException;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070059import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070060import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070061import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070062import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070063import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070064import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070065import android.database.sqlite.SQLiteStatement;
Doug Zongker885cfc232009-10-21 16:52:44 -070066import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070067import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080068import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070069import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070070import android.os.IBinder;
71import android.os.Looper;
72import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070073import android.os.Parcel;
Amith Yamasani27db4682013-03-30 17:07:47 -070074import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070075import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070076import android.os.RemoteException;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080077import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070078import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070079import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070080import android.os.UserManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070081import android.text.TextUtils;
82import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070083import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070084import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080085import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070086import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070087
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070088import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070089import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070090import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070091import com.android.internal.content.PackageMonitor;
Chris Wren282cfef2017-03-27 15:01:44 -040092import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050093import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080094import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060095import com.android.internal.util.DumpUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080096import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -070097import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000098import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -070099import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600100import com.android.server.SystemService;
101
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700102import com.google.android.collect.Lists;
103import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700104
Oscar Montemayora8529f62009-11-18 10:14:20 -0800105import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700106import java.io.FileDescriptor;
107import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800108import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700109import java.security.MessageDigest;
110import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700111import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700112import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800113import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700114import java.util.Collection;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700115import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700116import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700117import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800118import java.util.LinkedHashMap;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700119import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800120import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800121import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700122import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700123import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700124import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700125import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700126import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700127
Fred Quintana60307342009-03-24 22:48:12 -0700128/**
129 * A system service that provides account, password, and authtoken management for all
130 * accounts on the device. Some of these calls are implemented with the help of the corresponding
131 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
132 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700133 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700134 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700135 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700136public class AccountManagerService
137 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800138 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700139 private static final String TAG = "AccountManagerService";
140
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600141 public static class Lifecycle extends SystemService {
142 private AccountManagerService mService;
143
144 public Lifecycle(Context context) {
145 super(context);
146 }
147
148 @Override
149 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700150 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600151 publishBinderService(Context.ACCOUNT_SERVICE, mService);
152 }
153
154 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600155 public void onUnlockUser(int userHandle) {
156 mService.onUnlockUser(userHandle);
157 }
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -0700158
159 @Override
160 public void onCleanupUser(int userHandle) {
161 mService.onCleanupUser(userHandle);
162 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600163 }
164
Svet Ganov5d09c992016-09-07 09:57:41 -0700165 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700166
Fred Quintana56285a62010-12-02 14:20:51 -0800167 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700168 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700169 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700170 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800171
Svet Ganov5d09c992016-09-07 09:57:41 -0700172 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700173
Fred Quintana60307342009-03-24 22:48:12 -0700174 // Messages that can be sent on mHandler
175 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700176 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700177
Fred Quintana56285a62010-12-02 14:20:51 -0800178 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700179 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700180 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800181
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800182 private static final int SIGNATURE_CHECK_MISMATCH = 0;
183 private static final int SIGNATURE_CHECK_MATCH = 1;
184 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
185
Carlos Valdivia91979be2015-05-22 14:11:35 -0700186 static {
187 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800188 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
189 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700190 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700191
192 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700193
Amith Yamasani04e0d262012-02-14 11:50:53 -0800194 static class UserAccounts {
195 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700196 final AccountsDb accountsDb;
Chris Wren717a8812017-03-31 15:34:39 -0400197 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
198 credentialsPermissionNotificationIds = new HashMap<>();
199 private final HashMap<Account, NotificationId> signinRequiredNotificationIds
200 = new HashMap<>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700201 final Object cacheLock = new Object();
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700202 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
Amith Yamasani04e0d262012-02-14 11:50:53 -0800203 /** protected by the {@link #cacheLock} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700204 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800205 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700206 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800207 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700208 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700209 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700210 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700211 /** protected by the {@link #cacheLock} */
212 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700213
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700214 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700215 * type -> (packageName -> number of active receivers)
216 * type == null is used to get notifications about all account types
217 */
218 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800219
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700220 /**
221 * protected by the {@link #cacheLock}
222 *
223 * Caches the previous names associated with an account. Previous names
224 * should be cached because we expect that when an Account is renamed,
225 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
226 * want to know if the accounts they care about have been renamed.
227 *
228 * The previous names are wrapped in an {@link AtomicReference} so that
229 * we can distinguish between those accounts with no previous names and
230 * those whose previous names haven't been cached (yet).
231 */
232 private final HashMap<Account, AtomicReference<String>> previousNameCache =
233 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800234
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700235 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700236 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700237
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700238 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800239 this.userId = userId;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700240 synchronized (dbLock) {
241 synchronized (cacheLock) {
242 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
243 }
Amith Yamasani04e0d262012-02-14 11:50:53 -0800244 }
245 }
246 }
247
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700248 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600249 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700250 // Not thread-safe. Only use in synchronized context
251 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700252 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
253 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800254
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700255 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700256 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700257
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700258 /**
259 * This should only be called by system code. One should only call this after the service
260 * has started.
261 * @return a reference to the AccountManagerService instance
262 * @hide
263 */
264 public static AccountManagerService getSingleton() {
265 return sThis.get();
266 }
Fred Quintana60307342009-03-24 22:48:12 -0700267
Fyodor Kupolovda993802016-09-21 14:47:10 -0700268 public AccountManagerService(Injector injector) {
269 mInjector = injector;
270 mContext = injector.getContext();
271 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700272 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700273 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
274 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800275 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700276
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700277 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800278
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800279 IntentFilter intentFilter = new IntentFilter();
280 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
281 intentFilter.addDataScheme("package");
282 mContext.registerReceiver(new BroadcastReceiver() {
283 @Override
284 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700285 // Don't delete accounts when updating a authenticator's
286 // package.
287 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700288 /* Purging data requires file io, don't block the main thread. This is probably
289 * less than ideal because we are introducing a race condition where old grants
290 * could be exercised until they are purged. But that race condition existed
291 * anyway with the broadcast receiver.
292 *
293 * Ideally, we would completely clear the cache, purge data from the database,
294 * and then rebuild the cache. All under the cache lock. But that change is too
295 * large at this point.
296 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800297 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700298 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700299 @Override
300 public void run() {
301 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800302 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800303 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700304 }
305 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700306 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700307 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800308 }
309 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800310
Fyodor Kupolovda993802016-09-21 14:47:10 -0700311 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700312
313 // Need to cancel account request notifications if the update/install can access the account
314 new PackageMonitor() {
315 @Override
316 public void onPackageAdded(String packageName, int uid) {
317 // Called on a handler, and running as the system
318 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
319 }
320
321 @Override
322 public void onPackageUpdateFinished(String packageName, int uid) {
323 // Called on a handler, and running as the system
324 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
325 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700326 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700327
328 // Cancel account request notification if an app op was preventing the account access
329 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
330 new AppOpsManager.OnOpChangedInternalListener() {
331 @Override
332 public void onOpChanged(int op, String packageName) {
333 try {
334 final int userId = ActivityManager.getCurrentUser();
335 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
336 final int mode = mAppOpsManager.checkOpNoThrow(
337 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
338 if (mode == AppOpsManager.MODE_ALLOWED) {
339 final long identity = Binder.clearCallingIdentity();
340 try {
341 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
342 } finally {
343 Binder.restoreCallingIdentity(identity);
344 }
345 }
346 } catch (NameNotFoundException e) {
347 /* ignore */
348 }
349 }
350 });
351
352 // Cancel account request notification if a permission was preventing the account access
353 mPackageManager.addOnPermissionsChangeListener(
354 (int uid) -> {
355 Account[] accounts = null;
356 String[] packageNames = mPackageManager.getPackagesForUid(uid);
357 if (packageNames != null) {
358 final int userId = UserHandle.getUserId(uid);
359 final long identity = Binder.clearCallingIdentity();
360 try {
361 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800362 // if app asked for permission we need to cancel notification even
363 // for O+ applications.
364 if (mPackageManager.checkPermission(
365 Manifest.permission.GET_ACCOUNTS,
366 packageName) != PackageManager.PERMISSION_GRANTED) {
367 continue;
368 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700369
370 if (accounts == null) {
371 accounts = getAccountsAsUser(null, userId, "android");
372 if (ArrayUtils.isEmpty(accounts)) {
373 return;
374 }
375 }
376
377 for (Account account : accounts) {
378 cancelAccountAccessRequestNotificationIfNeeded(
379 account, uid, packageName, true);
380 }
381 }
382 } finally {
383 Binder.restoreCallingIdentity(identity);
384 }
385 }
386 });
387 }
388
389 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
390 boolean checkAccess) {
391 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
392 for (Account account : accounts) {
393 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
394 }
395 }
396
397 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
398 boolean checkAccess) {
399 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
400 for (Account account : accounts) {
401 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
402 }
403 }
404
405 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
406 boolean checkAccess) {
407 String[] packageNames = mPackageManager.getPackagesForUid(uid);
408 if (packageNames != null) {
409 for (String packageName : packageNames) {
410 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
411 packageName, checkAccess);
412 }
413 }
414 }
415
416 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
417 int uid, String packageName, boolean checkAccess) {
418 if (!checkAccess || hasAccountAccess(account, packageName,
419 UserHandle.getUserHandleForUid(uid))) {
420 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700421 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700422 UserHandle.getUserHandleForUid(uid));
423 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800424 }
425
Dianne Hackborn164371f2013-10-01 19:10:13 -0700426 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800427 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800428 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800429 Bundle.setDefusable(extras, true);
430
431 final int callingUid = Binder.getCallingUid();
432 if (Log.isLoggable(TAG, Log.VERBOSE)) {
433 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
434 + ", pid " + Binder.getCallingPid());
435 }
436 Preconditions.checkNotNull(account, "account cannot be null");
437 int userId = UserHandle.getCallingUserId();
438 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
439 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
440 callingUid, account.type);
441 throw new SecurityException(msg);
442 }
443 /*
444 * Child users are not allowed to add accounts. Only the accounts that are shared by the
445 * parent profile can be added to child profile.
446 *
447 * TODO: Only allow accounts that were shared to be added by a limited user.
448 */
449 // fails if the account already exists
450 long identityToken = clearCallingIdentity();
451 try {
452 UserAccounts accounts = getUserAccounts(userId);
453 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800454 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800455 } finally {
456 restoreCallingIdentity(identityToken);
457 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700458 }
459
460 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800461 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
462 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800463 int callingUid = Binder.getCallingUid();
464 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
465 List<String> managedTypes =
466 getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
467
468 if ((accountType != null && !managedTypes.contains(accountType))
469 || (accountType == null && !isSystemUid)) {
470 throw new SecurityException(
471 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
472 + callingUid + " with packageName=" + packageName);
473 }
474 if (accountType != null) {
475 managedTypes = new ArrayList<String>();
476 managedTypes.add(accountType);
477 }
478
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800479 long identityToken = clearCallingIdentity();
480 try {
481 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
482 getUserAccounts(UserHandle.getUserId(callingUid)));
483 } finally {
484 restoreCallingIdentity(identityToken);
485 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800486 }
487
488 /*
489 * accountTypes may not be null
490 */
491 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
492 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
493 int uid = 0;
494 try {
495 uid = mPackageManager.getPackageUidAsUser(packageName,
496 UserHandle.getUserId(callingUid));
497 } catch (NameNotFoundException e) {
498 Log.d(TAG, "Package not found " + e.getMessage());
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800499 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800500 }
501
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800502 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800503 for (String accountType : accountTypes) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700504 synchronized (accounts.dbLock) {
505 synchronized (accounts.cacheLock) {
506 final Account[] accountsOfType = accounts.accountCache.get(accountType);
507 if (accountsOfType != null) {
508 for (Account account : accountsOfType) {
509 result.put(account,
510 resolveAccountVisibility(account, packageName, accounts));
511 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800512 }
513 }
514 }
515 }
516 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800517 }
518
519 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800520 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700521 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700522 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800523 int userId = UserHandle.getUserId(callingUid);
524 UserAccounts accounts = getUserAccounts(userId);
525 if (!isAccountManagedByCaller(account.type, callingUid, userId)
526 && !isSystemUid(callingUid)) {
527 String msg =
528 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700529 throw new SecurityException(msg);
530 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700531 synchronized (accounts.dbLock) {
532 synchronized (accounts.cacheLock) {
533 return getPackagesAndVisibilityForAccountLocked(account, accounts);
534 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700535 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800536 }
537
538 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700539 * Returns Map with all package names and visibility values for given account.
540 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800541 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800542 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800543 * @param accounts UserAccount that currently hosts the account and application
544 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700545 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800546 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700547 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800548 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700549 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
550 if (accountVisibility == null) {
551 Log.d(TAG, "Visibility was not initialized");
552 accountVisibility = new HashMap<>();
553 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800554 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700555 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700556 }
557
558 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700559 public int getAccountVisibility(Account account, String packageName) {
560 Preconditions.checkNotNull(account, "account cannot be null");
561 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800562 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700563 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
564 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800565 && !isSystemUid(callingUid)) {
566 String msg = String.format(
567 "uid %s cannot get secrets for accounts of type: %s",
568 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700569 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800570 throw new SecurityException(msg);
571 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700572 return resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800573 }
574
575 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800576 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800577 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800578 * @param account The account to check visibility.
579 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800580 * @param accounts UserAccount that currently hosts the account and application
581 *
582 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
583 *
584 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700585 private int getAccountVisibilityFromCache(Account account, String packageName,
586 UserAccounts accounts) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -0700587 synchronized (accounts.cacheLock) {
588 Map<String, Integer> accountVisibility =
589 getPackagesAndVisibilityForAccountLocked(account, accounts);
590 Integer visibility = accountVisibility.get(packageName);
591 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800592 }
593 }
594
595 /**
596 * Method which handles default values for Account visibility.
597 *
598 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800599 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800600 * @param accounts UserAccount that currently hosts the account and application
601 *
602 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
603 *
604 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800605 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800606 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800607 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800608 int uid = -1;
609 try {
610 long identityToken = clearCallingIdentity();
611 try {
612 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
613 } finally {
614 restoreCallingIdentity(identityToken);
615 }
616 } catch (NameNotFoundException e) {
617 Log.d(TAG, "Package not found " + e.getMessage());
618 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800619 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800620
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800621 // System visibility can not be restricted.
622 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
623 return AccountManager.VISIBILITY_VISIBLE;
624 }
625
626 int signatureCheckResult =
627 checkPackageSignature(account.type, uid, accounts.userId);
628
629 // Authenticator can not restrict visibility to itself.
630 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
631 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
632 }
633
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800634 if (isSpecialPackageKey(packageName)) {
635 Log.d(TAG, "Package name is forbidden: " + packageName);
636 return AccountManager.VISIBILITY_NOT_VISIBLE;
637 }
638
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800639 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700640 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800641
642 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
643 return visibility;
644 }
645
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800646 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
647 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
648
649 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800650 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800651 return AccountManager.VISIBILITY_VISIBLE;
652 }
653 // Apps with READ_CONTACTS permission get visibility by default even post O.
654 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
655
656 boolean preO = isPreOApplication(packageName);
657 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
658 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800659 || canReadContacts || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800660 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
661 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700662 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800663 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800664 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
665 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
666 }
667 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700668 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800669 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800670 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
671 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
672 }
673 }
674 return visibility;
675 }
676
677 /**
678 * Checks targetSdk for a package;
679 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800680 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800681 *
682 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
683 * undefined
684 */
685 private boolean isPreOApplication(String packageName) {
686 try {
687 long identityToken = clearCallingIdentity();
688 ApplicationInfo applicationInfo;
689 try {
690 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
691 } finally {
692 restoreCallingIdentity(identityToken);
693 }
694
695 if (applicationInfo != null) {
696 int version = applicationInfo.targetSdkVersion;
697 return version < android.os.Build.VERSION_CODES.O;
698 }
699 return true;
700 } catch (NameNotFoundException e) {
701 Log.d(TAG, "Package not found " + e.getMessage());
702 return true;
703 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800704 }
705
706 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700707 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
708 Preconditions.checkNotNull(account, "account cannot be null");
709 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800710 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700711 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
712 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800713 && !isSystemUid(callingUid)) {
714 String msg = String.format(
715 "uid %s cannot get secrets for accounts of type: %s",
716 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700717 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800718 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700719 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700720 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
721 accounts);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700722 }
723
724 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800725 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700726 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800727 * @param account Account to update visibility.
728 * @param packageName Package name for which visibility is updated.
729 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800730 * @param notify if the flag is set applications will get notification about visibility change
731 * @param accounts UserAccount that currently hosts the account and application
732 *
733 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700734 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800735 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800736 boolean notify, UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700737 synchronized (accounts.dbLock) {
738 synchronized (accounts.cacheLock) {
739 Map<String, Integer> packagesToVisibility;
740 if (notify) {
741 if (isSpecialPackageKey(packageName)) {
742 packagesToVisibility =
743 getRequestingPackages(account, accounts);
744 } else {
745 if (!packageExistsForUser(packageName, accounts.userId)) {
746 return false; // package is not installed.
747 }
748 packagesToVisibility = new HashMap<>();
749 packagesToVisibility.put(packageName,
750 resolveAccountVisibility(account, packageName, accounts));
751 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800752 } else {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700753 // Notifications will not be send.
754 if (!isSpecialPackageKey(packageName) &&
755 !packageExistsForUser(packageName, accounts.userId)) {
756 // package is not installed and not meta value.
757 return false;
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100758 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700759 packagesToVisibility = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800760 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700761
762 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800763 return false;
764 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800765
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700766 if (notify) {
767 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
768 .entrySet()) {
769 if (packageToVisibility.getValue()
770 != AccountManager.VISIBILITY_NOT_VISIBLE) {
771 notifyPackage(packageToVisibility.getKey(), accounts);
772 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700773 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700774 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700775 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700776 return true;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800777 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700778 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700779 }
780
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700781 // Update account visibility in cache and database.
782 private boolean updateAccountVisibilityLocked(Account account, String packageName,
783 int newVisibility, UserAccounts accounts) {
784 final long accountId = accounts.accountsDb.findDeAccountId(account);
785 if (accountId < 0) {
786 return false;
787 }
788
789 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
790 try {
791 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
792 newVisibility)) {
793 return false;
794 }
795 } finally {
796 StrictMode.setThreadPolicy(oldPolicy);
797 }
798 Map<String, Integer> accountVisibility =
799 getPackagesAndVisibilityForAccountLocked(account, accounts);
800 accountVisibility.put(packageName, newVisibility);
801 return true;
802 }
803
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700804 @Override
805 public void registerAccountListener(String[] accountTypes, String opPackageName) {
806 int callingUid = Binder.getCallingUid();
807 mAppOpsManager.checkPackage(callingUid, opPackageName);
808 registerAccountListener(accountTypes, opPackageName,
809 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800810 }
811
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700812 private void registerAccountListener(String[] accountTypes, String opPackageName,
813 UserAccounts accounts) {
814 synchronized (accounts.mReceiversForType) {
815 if (accountTypes == null) {
816 // null for any type
817 accountTypes = new String[] {null};
818 }
819 for (String type : accountTypes) {
820 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
821 if (receivers == null) {
822 receivers = new HashMap<>();
823 accounts.mReceiversForType.put(type, receivers);
824 }
825 Integer cnt = receivers.get(opPackageName);
826 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800827 }
828 }
829 }
830
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700831 @Override
832 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
833 int callingUid = Binder.getCallingUid();
834 mAppOpsManager.checkPackage(callingUid, opPackageName);
835 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
836 synchronized (accounts.mReceiversForType) {
837 if (accountTypes == null) {
838 // null for any type
839 accountTypes = new String[] {null};
840 }
841 for (String type : accountTypes) {
842 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
843 if (receivers == null || receivers.get(opPackageName) == null) {
844 throw new IllegalArgumentException("attempt to unregister wrong receiver");
845 }
846 Integer cnt = receivers.get(opPackageName);
847 if (cnt == 1) {
848 receivers.remove(opPackageName);
849 } else {
850 receivers.put(opPackageName, cnt - 1);
851 }
852 }
853 }
854 }
855
856 // Send notification to all packages which can potentially see the account
857 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
858 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
859 // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
860 // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
861 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
862 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
863 notifyPackage(packageToVisibility.getKey(), accounts);
864 }
865 }
866 }
867
868 /**
869 * Sends a direct intent to a package, notifying it of account visibility change.
870 *
871 * @param packageName to send Account to
872 * @param accounts UserAccount that currently hosts the account
873 */
874 private void notifyPackage(String packageName, UserAccounts accounts) {
875 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
876 intent.setPackage(packageName);
877 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
878 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
879 }
880
881 // Returns a map from package name to visibility, for packages subscribed
882 // to notifications about any account type, or type of provided account
883 // account type or all types.
884 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
885 Set<String> packages = new HashSet<>();
886 synchronized (accounts.mReceiversForType) {
887 for (String type : new String[] {account.type, null}) {
888 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
889 if (receivers != null) {
890 packages.addAll(receivers.keySet());
891 }
892 }
893 }
894 Map<String, Integer> result = new HashMap<>();
895 for (String packageName : packages) {
896 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
897 }
898 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800899 }
900
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800901 private boolean packageExistsForUser(String packageName, int userId) {
902 try {
903 long identityToken = clearCallingIdentity();
904 try {
905 mPackageManager.getPackageUidAsUser(packageName, userId);
906 return true; // package exist
907 } finally {
908 restoreCallingIdentity(identityToken);
909 }
910 } catch (NameNotFoundException e) {
911 return false;
912 }
913 }
914
915 /**
916 * Returns true if packageName is one of special values.
917 */
918 private boolean isSpecialPackageKey(String packageName) {
919 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
920 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
921 }
922
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800923 private void sendAccountsChangedBroadcast(int userId) {
924 Log.i(TAG, "the accounts changed, sending broadcast of "
925 + ACCOUNTS_CHANGED_INTENT.getAction());
926 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700927 }
928
929 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700930 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
931 throws RemoteException {
932 try {
933 return super.onTransact(code, data, reply, flags);
934 } catch (RuntimeException e) {
935 // The account manager only throws security exceptions, so let's
936 // log all others.
937 if (!(e instanceof SecurityException)) {
938 Slog.wtf(TAG, "Account Manager Crash", e);
939 }
940 throw e;
941 }
942 }
943
Amith Yamasani258848d2012-08-10 17:06:33 -0700944 private UserManager getUserManager() {
945 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700946 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700947 }
948 return mUserManager;
949 }
950
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700951 /**
952 * Validate internal set of accounts against installed authenticators for
953 * given user. Clears cached authenticators before validating.
954 */
955 public void validateAccounts(int userId) {
956 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700957 // Invalidate user-specific cache to make sure we catch any
958 // removed authenticators.
959 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
960 }
961
962 /**
963 * Validate internal set of accounts against installed authenticators for
964 * given user. Clear cached authenticators before validating when requested.
965 */
966 private void validateAccountsInternal(
967 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700968 if (Log.isLoggable(TAG, Log.DEBUG)) {
969 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700970 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600971 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700972 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700973
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700974 if (invalidateAuthenticatorCache) {
975 mAuthenticatorCache.invalidateCache(accounts.userId);
976 }
977
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700978 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
979 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700980 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700981
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700982 synchronized (accounts.dbLock) {
983 synchronized (accounts.cacheLock) {
984 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800985
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -0700986 // Get a map of stored authenticator types to UID
987 final AccountsDb accountsDb = accounts.accountsDb;
988 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
989 // Create a list of authenticator type whose previous uid no longer exists
990 HashSet<String> obsoleteAuthType = Sets.newHashSet();
991 SparseBooleanArray knownUids = null;
992 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
993 String type = authToUidEntry.getKey();
994 int uid = authToUidEntry.getValue();
995 Integer knownUid = knownAuth.get(type);
996 if (knownUid != null && uid == knownUid) {
997 // Remove it from the knownAuth list if it's unchanged.
998 knownAuth.remove(type);
999 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001000 /*
1001 * The authenticator is presently not cached and should only be triggered
1002 * when we think an authenticator has been removed (or is being updated).
1003 * But we still want to check if any data with the associated uid is
1004 * around. This is an (imperfect) signal that the package may be updating.
1005 *
1006 * A side effect of this is that an authenticator sharing a uid with
1007 * multiple apps won't get its credentials wiped as long as some app with
1008 * that uid is still on the device. But I suspect that this is a rare case.
1009 * And it isn't clear to me how an attacker could really exploit that
1010 * feature.
1011 *
1012 * The upshot is that we don't have to worry about accounts getting
1013 * uninstalled while the authenticator's package is being updated.
1014 *
1015 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001016 if (knownUids == null) {
1017 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
1018 }
1019 if (!knownUids.get(uid)) {
1020 // The authenticator is not presently available to the cache. And the
1021 // package no longer has a data directory (so we surmise it isn't
1022 // updating). So purge its data from the account databases.
1023 obsoleteAuthType.add(type);
1024 // And delete it from the TABLE_META
1025 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
1026 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001027 }
1028 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001029
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001030 // Add the newly registered authenticator to TABLE_META. If old authenticators have
1031 // been re-enabled (after being updated for example), then we just overwrite the old
1032 // values.
1033 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
1034 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
1035 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001036
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001037 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
1038 try {
1039 accounts.accountCache.clear();
1040 final HashMap<String, ArrayList<String>> accountNamesByType
1041 = new LinkedHashMap<>();
1042 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1043 final long accountId = accountEntry.getKey();
1044 final Account account = accountEntry.getValue();
1045 if (obsoleteAuthType.contains(account.type)) {
1046 Slog.w(TAG, "deleting account " + account.name + " because type "
1047 + account.type
1048 + "'s registered authenticator no longer exist.");
1049 Map<String, Integer> packagesToVisibility =
1050 getRequestingPackages(account, accounts);
1051 accountsDb.beginTransaction();
1052 try {
1053 accountsDb.deleteDeAccount(accountId);
1054 // Also delete from CE table if user is unlocked; if user is
1055 // currently locked the account will be removed later by
1056 // syncDeCeAccountsLocked
1057 if (userUnlocked) {
1058 accountsDb.deleteCeAccount(accountId);
1059 }
1060 accountsDb.setTransactionSuccessful();
1061 } finally {
1062 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001063 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001064 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001065
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001066 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1067 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001068
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001069 accounts.userDataCache.remove(account);
1070 accounts.authTokenCache.remove(account);
1071 accounts.accountTokenCaches.remove(account);
1072 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001073
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001074 for (Entry<String, Integer> packageToVisibility :
1075 packagesToVisibility.entrySet()) {
1076 if (packageToVisibility.getValue()
1077 != AccountManager.VISIBILITY_NOT_VISIBLE) {
1078 notifyPackage(packageToVisibility.getKey(), accounts);
1079 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001080 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001081 } else {
1082 ArrayList<String> accountNames = accountNamesByType.get(account.type);
1083 if (accountNames == null) {
1084 accountNames = new ArrayList<>();
1085 accountNamesByType.put(account.type, accountNames);
1086 }
1087 accountNames.add(account.name);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001088 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001089 }
1090 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
1091 final String accountType = cur.getKey();
1092 final ArrayList<String> accountNames = cur.getValue();
1093 final Account[] accountsForType = new Account[accountNames.size()];
1094 for (int i = 0; i < accountsForType.length; i++) {
1095 accountsForType[i] = new Account(accountNames.get(i), accountType,
1096 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001097 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001098 accounts.accountCache.put(accountType, accountsForType);
Fred Quintana56285a62010-12-02 14:20:51 -08001099 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001100 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
1101 } finally {
1102 if (accountDeleted) {
1103 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintana56285a62010-12-02 14:20:51 -08001104 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001105 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001106 }
1107 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001108 }
1109
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001110 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1111 // Get the UIDs of all apps that might have data on the device. We want
1112 // to preserve user data if the app might otherwise be storing data.
1113 List<PackageInfo> pkgsWithData =
1114 mPackageManager.getInstalledPackagesAsUser(
1115 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1116 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1117 for (PackageInfo pkgInfo : pkgsWithData) {
1118 if (pkgInfo.applicationInfo != null
1119 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1120 knownUids.put(pkgInfo.applicationInfo.uid, true);
1121 }
1122 }
1123 return knownUids;
1124 }
1125
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001126 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001127 Context context,
1128 int userId) {
1129 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001130 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1131 }
1132
1133 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1134 IAccountAuthenticatorCache authCache,
1135 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001136 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001137 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1138 .getAllServices(userId)) {
1139 knownAuth.put(service.type.type, service.uid);
1140 }
1141 return knownAuth;
1142 }
1143
Amith Yamasani04e0d262012-02-14 11:50:53 -08001144 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001145 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001146 }
1147
1148 protected UserAccounts getUserAccounts(int userId) {
1149 synchronized (mUsers) {
1150 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001151 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001152 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001153 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1154 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001155 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001156 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001157 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001158 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001159 validateAccounts = true;
1160 }
1161 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001162 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001163 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001164 synchronized (accounts.dbLock) {
1165 synchronized (accounts.cacheLock) {
1166 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
1167 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
1168 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001169 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001170 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001171 }
1172 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001173 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001174 }
1175 return accounts;
1176 }
1177 }
1178
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001179 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1180 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001181 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001182 if (!accountsToRemove.isEmpty()) {
1183 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1184 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001185 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1186 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001187
1188 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001189 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001190 }
1191 }
1192 }
1193
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001194 private void purgeOldGrantsAll() {
1195 synchronized (mUsers) {
1196 for (int i = 0; i < mUsers.size(); i++) {
1197 purgeOldGrants(mUsers.valueAt(i));
1198 }
1199 }
1200 }
1201
1202 private void purgeOldGrants(UserAccounts accounts) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001203 synchronized (accounts.dbLock) {
1204 synchronized (accounts.cacheLock) {
1205 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
1206 for (int uid : uids) {
1207 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1208 if (packageExists) {
1209 continue;
1210 }
1211 Log.d(TAG, "deleting grants for UID " + uid
1212 + " because its package is no longer installed");
1213 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001214 }
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001215 }
1216 }
1217 }
1218
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001219 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001220 if (isSpecialPackageKey(packageName)) {
1221 return;
1222 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001223 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001224 int numberOfUsers = mUsers.size();
1225 for (int i = 0; i < numberOfUsers; i++) {
1226 UserAccounts accounts = mUsers.valueAt(i);
1227 try {
1228 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1229 } catch (NameNotFoundException e) {
1230 // package does not exist - remove visibility values
1231 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001232 synchronized (accounts.dbLock) {
1233 synchronized (accounts.cacheLock) {
1234 for (Account account : accounts.visibilityCache.keySet()) {
1235 Map<String, Integer> accountVisibility =
1236 getPackagesAndVisibilityForAccountLocked(account, accounts);
1237 accountVisibility.remove(packageName);
1238 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001239 }
1240 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001241 }
1242 }
1243 }
1244 }
1245
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001246
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -07001247 private void onCleanupUser(int userId) {
1248 Log.i(TAG, "onCleanupUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001249 UserAccounts accounts;
1250 synchronized (mUsers) {
1251 accounts = mUsers.get(userId);
1252 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001253 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001254 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001255 if (accounts != null) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001256 synchronized (accounts.dbLock) {
1257 synchronized (accounts.cacheLock) {
1258 accounts.accountsDb.close();
1259 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001260 }
Amith Yamasani13593602012-03-22 16:16:17 -07001261 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001262 }
1263
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001264 @VisibleForTesting
1265 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001266 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1267 }
1268
1269 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001270 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1271 Log.v(TAG, "onUserUnlocked " + userId);
1272 }
1273 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001274 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001275 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001276 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001277 syncSharedAccounts(userId);
1278 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001279
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001280 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001281 // Check if there's a shared account that needs to be created as an account
1282 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1283 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001284 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001285 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001286 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001287 : UserHandle.USER_SYSTEM;
1288 if (parentUserId < 0) {
1289 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1290 return;
1291 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001292 for (Account sa : sharedAccounts) {
1293 if (ArrayUtils.contains(accounts, sa)) continue;
1294 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001295 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001296 }
1297 }
1298
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001299 @Override
1300 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001301 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001302 }
1303
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001304 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001305 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001306 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001307 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1308 Log.v(TAG, "getPassword: " + account
1309 + ", caller's uid " + Binder.getCallingUid()
1310 + ", pid " + Binder.getCallingPid());
1311 }
Fred Quintana382601f2010-03-25 12:25:10 -07001312 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001313 int userId = UserHandle.getCallingUserId();
1314 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001315 String msg = String.format(
1316 "uid %s cannot get secrets for accounts of type: %s",
1317 callingUid,
1318 account.type);
1319 throw new SecurityException(msg);
1320 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001321 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001322 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001323 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001324 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001325 } finally {
1326 restoreCallingIdentity(identityToken);
1327 }
1328 }
1329
Amith Yamasani04e0d262012-02-14 11:50:53 -08001330 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001331 if (account == null) {
1332 return null;
1333 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001334 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001335 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1336 return null;
1337 }
Fred Quintana31957f12009-10-21 13:43:10 -07001338
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001339 synchronized (accounts.dbLock) {
1340 synchronized (accounts.cacheLock) {
1341 return accounts.accountsDb
1342 .findAccountPasswordByNameAndType(account.name, account.type);
1343 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001344 }
1345 }
1346
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001347 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001348 public String getPreviousName(Account account) {
1349 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1350 Log.v(TAG, "getPreviousName: " + account
1351 + ", caller's uid " + Binder.getCallingUid()
1352 + ", pid " + Binder.getCallingPid());
1353 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001354 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001355 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001356 long identityToken = clearCallingIdentity();
1357 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001358 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001359 return readPreviousNameInternal(accounts, account);
1360 } finally {
1361 restoreCallingIdentity(identityToken);
1362 }
1363 }
1364
1365 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1366 if (account == null) {
1367 return null;
1368 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001369 synchronized (accounts.dbLock) {
1370 synchronized (accounts.cacheLock) {
1371 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1372 if (previousNameRef == null) {
1373 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
1374 previousNameRef = new AtomicReference<>(previousName);
1375 accounts.previousNameCache.put(account, previousNameRef);
1376 return previousName;
1377 } else {
1378 return previousNameRef.get();
1379 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001380 }
1381 }
1382 }
1383
1384 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001385 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001386 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001387 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001388 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1389 account, key, callingUid, Binder.getCallingPid());
1390 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001391 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001392 Preconditions.checkNotNull(account, "account cannot be null");
1393 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001394 int userId = UserHandle.getCallingUserId();
1395 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001396 String msg = String.format(
1397 "uid %s cannot get user data for accounts of type: %s",
1398 callingUid,
1399 account.type);
1400 throw new SecurityException(msg);
1401 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001402 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001403 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1404 return null;
1405 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001406 long identityToken = clearCallingIdentity();
1407 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001408 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001409 if (!accountExistsCache(accounts, account)) {
1410 return null;
Simranjit Kohli858511c2016-03-10 18:36:11 +00001411 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07001412 return readUserDataInternal(accounts, account, key);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001413 } finally {
1414 restoreCallingIdentity(identityToken);
1415 }
1416 }
1417
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001418 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001419 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001420 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001421 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1422 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001423 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001424 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001425 + ", pid " + Binder.getCallingPid());
1426 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001427 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001428 if (isCrossUser(callingUid, userId)) {
1429 throw new SecurityException(
1430 String.format(
1431 "User %s tying to get authenticator types for %s" ,
1432 UserHandle.getCallingUserId(),
1433 userId));
1434 }
1435
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001436 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001437 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001438 return getAuthenticatorTypesInternal(userId);
1439
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001440 } finally {
1441 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001442 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001443 }
1444
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001445 /**
1446 * Should only be called inside of a clearCallingIdentity block.
1447 */
1448 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001449 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001450 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1451 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1452 AuthenticatorDescription[] types =
1453 new AuthenticatorDescription[authenticatorCollection.size()];
1454 int i = 0;
1455 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1456 : authenticatorCollection) {
1457 types[i] = authenticator.type;
1458 i++;
1459 }
1460 return types;
1461 }
1462
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001463 private boolean isCrossUser(int callingUid, int userId) {
1464 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001465 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001466 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001467 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1468 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001469 }
1470
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001471 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001472 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001473 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001474 }
1475
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001476 @Override
1477 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001478 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001479 int callingUid = Binder.getCallingUid();
1480 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1481 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001482 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001483 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001484 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1485 final UserAccounts toAccounts = getUserAccounts(userTo);
1486 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001487 if (response != null) {
1488 Bundle result = new Bundle();
1489 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1490 try {
1491 response.onResult(result);
1492 } catch (RemoteException e) {
1493 Slog.w(TAG, "Failed to report error back to the client." + e);
1494 }
1495 }
1496 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001497 }
1498
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001499 Slog.d(TAG, "Copying account " + account.name
1500 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001501 long identityToken = clearCallingIdentity();
1502 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001503 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001504 false /* stripAuthTokenFromResult */, account.name,
1505 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001506 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001507 protected String toDebugString(long now) {
1508 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1509 + ", " + account.type;
1510 }
1511
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001512 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001513 public void run() throws RemoteException {
1514 mAuthenticator.getAccountCredentialsForCloning(this, account);
1515 }
1516
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001517 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001518 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001519 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001520 if (result != null
1521 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1522 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001523 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001524 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001525 super.onResult(result);
1526 }
1527 }
1528 }.bind();
1529 } finally {
1530 restoreCallingIdentity(identityToken);
1531 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001532 }
1533
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001534 @Override
1535 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001536 final int callingUid = Binder.getCallingUid();
1537 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1538 String msg = String.format(
1539 "accountAuthenticated( account: %s, callerUid: %s)",
1540 account,
1541 callingUid);
1542 Log.v(TAG, msg);
1543 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001544 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001545 int userId = UserHandle.getCallingUserId();
1546 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001547 String msg = String.format(
1548 "uid %s cannot notify authentication for accounts of type: %s",
1549 callingUid,
1550 account.type);
1551 throw new SecurityException(msg);
1552 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001553
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001554 if (!canUserModifyAccounts(userId, callingUid) ||
1555 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001556 return false;
1557 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001558
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001559 long identityToken = clearCallingIdentity();
1560 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001561 UserAccounts accounts = getUserAccounts(userId);
1562 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001563 } finally {
1564 restoreCallingIdentity(identityToken);
1565 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001566 }
1567
1568 private boolean updateLastAuthenticatedTime(Account account) {
1569 final UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001570 synchronized (accounts.dbLock) {
1571 synchronized (accounts.cacheLock) {
1572 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
1573 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001574 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001575 }
1576
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001577 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001578 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1579 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001580 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001581 long id = clearCallingIdentity();
1582 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001583 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001584 false /* stripAuthTokenFromResult */, account.name,
1585 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001586 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001587 protected String toDebugString(long now) {
1588 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1589 + ", " + account.type;
1590 }
1591
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001592 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001593 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001594 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov16bedd42017-03-30 10:00:49 -07001595 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) {
1596 if (acc.equals(account)) {
1597 mAuthenticator.addAccountFromCredentials(
1598 this, account, accountCredentials);
1599 break;
Amith Yamasani5be347b2013-03-31 17:44:31 -07001600 }
1601 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001602 }
1603
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001604 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001605 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001606 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001607 // TODO: Anything to do if if succedded?
1608 // TODO: If it failed: Show error notification? Should we remove the shadow
1609 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001610 // TODO: what we do with the visibility?
1611
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001612 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001613 }
1614
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001615 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001616 public void onError(int errorCode, String errorMessage) {
1617 super.onError(errorCode, errorMessage);
1618 // TODO: Show error notification to user
1619 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1620 }
1621
1622 }.bind();
1623 } finally {
1624 restoreCallingIdentity(id);
1625 }
1626 }
1627
Amith Yamasani04e0d262012-02-14 11:50:53 -08001628 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001629 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001630 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001631 if (account == null) {
1632 return false;
1633 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001634 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001635 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1636 + " is locked. callingUid=" + callingUid);
1637 return false;
1638 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001639 synchronized (accounts.dbLock) {
1640 synchronized (accounts.cacheLock) {
1641 accounts.accountsDb.beginTransaction();
1642 try {
1643 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
1644 Log.w(TAG, "insertAccountIntoDatabase: " + account
1645 + ", skipping since the account already exists");
1646 return false;
1647 }
1648 long accountId = accounts.accountsDb.insertCeAccount(account, password);
1649 if (accountId < 0) {
1650 Log.w(TAG, "insertAccountIntoDatabase: " + account
1651 + ", skipping the DB insert failed");
1652 return false;
1653 }
1654 // Insert into DE table
1655 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
1656 Log.w(TAG, "insertAccountIntoDatabase: " + account
1657 + ", skipping the DB insert failed");
1658 return false;
1659 }
1660 if (extras != null) {
1661 for (String key : extras.keySet()) {
1662 final String value = extras.getString(key);
1663 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
1664 Log.w(TAG, "insertAccountIntoDatabase: " + account
1665 + ", skipping since insertExtra failed for key " + key);
1666 return false;
1667 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001668 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001669 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001670
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001671 if (packageToVisibility != null) {
1672 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1673 setAccountVisibility(account, entry.getKey() /* package */,
1674 entry.getValue() /* visibility */, false /* notify */,
1675 accounts);
1676 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001677 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001678 accounts.accountsDb.setTransactionSuccessful();
1679
1680 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
1681 accountId,
1682 accounts, callingUid);
1683
1684 insertAccountIntoCacheLocked(accounts, account);
1685 } finally {
1686 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001687 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001688 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001689 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001690 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1691 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001692 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001693
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001694 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001695 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1696 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001697
Amith Yamasani5be347b2013-03-31 17:44:31 -07001698 return true;
1699 }
1700
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001701 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001702 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001703 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001704 }
1705 }
1706
Amith Yamasani5be347b2013-03-31 17:44:31 -07001707 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001708 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001709 * running, then clone the account too.
1710 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001711 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001712 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001713 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001714 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001715 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001716 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001717 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001718 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001719 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001720 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001721 }
1722 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001723 }
1724 }
1725
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001726 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001727 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001728 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001729 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001730 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001731 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1732 Log.v(TAG, "hasFeatures: " + account
1733 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001734 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001735 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001736 + ", pid " + Binder.getCallingPid());
1737 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001738 Preconditions.checkArgument(account != null, "account cannot be null");
1739 Preconditions.checkArgument(response != null, "response cannot be null");
1740 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001741 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001742 checkReadAccountsPermitted(callingUid, account.type, userId,
1743 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001744
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001745 long identityToken = clearCallingIdentity();
1746 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001747 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001748 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001749 } finally {
1750 restoreCallingIdentity(identityToken);
1751 }
1752 }
1753
1754 private class TestFeaturesSession extends Session {
1755 private final String[] mFeatures;
1756 private final Account mAccount;
1757
Amith Yamasani04e0d262012-02-14 11:50:53 -08001758 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001759 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001760 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001761 true /* stripAuthTokenFromResult */, account.name,
1762 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001763 mFeatures = features;
1764 mAccount = account;
1765 }
1766
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001767 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001768 public void run() throws RemoteException {
1769 try {
1770 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1771 } catch (RemoteException e) {
1772 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1773 }
1774 }
1775
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001776 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001777 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001778 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001779 IAccountManagerResponse response = getResponseAndClose();
1780 if (response != null) {
1781 try {
1782 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001783 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001784 return;
1785 }
Fred Quintana56285a62010-12-02 14:20:51 -08001786 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1787 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1788 + response);
1789 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001790 final Bundle newResult = new Bundle();
1791 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1792 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1793 response.onResult(newResult);
1794 } catch (RemoteException e) {
1795 // if the caller is dead then there is no one to care about remote exceptions
1796 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1797 Log.v(TAG, "failure while notifying response", e);
1798 }
1799 }
1800 }
1801 }
1802
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001803 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001804 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001805 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001806 + ", " + mAccount
1807 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1808 }
1809 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001810
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001811 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001812 public void renameAccount(
1813 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001814 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001815 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1816 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001817 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001818 + ", pid " + Binder.getCallingPid());
1819 }
1820 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001821 int userId = UserHandle.getCallingUserId();
1822 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001823 String msg = String.format(
1824 "uid %s cannot rename accounts of type: %s",
1825 callingUid,
1826 accountToRename.type);
1827 throw new SecurityException(msg);
1828 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001829 long identityToken = clearCallingIdentity();
1830 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001831 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001832 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001833 Bundle result = new Bundle();
1834 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1835 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001836 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1837 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001838 try {
1839 response.onResult(result);
1840 } catch (RemoteException e) {
1841 Log.w(TAG, e.getMessage());
1842 }
1843 } finally {
1844 restoreCallingIdentity(identityToken);
1845 }
1846 }
1847
1848 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001849 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001850 Account resultAccount = null;
1851 /*
1852 * Cancel existing notifications. Let authenticators
1853 * re-post notifications as required. But we don't know if
1854 * the authenticators have bound their notifications to
1855 * now stale account name data.
1856 *
1857 * With a rename api, we might not need to do this anymore but it
1858 * shouldn't hurt.
1859 */
1860 cancelNotification(
1861 getSigninRequiredNotificationId(accounts, accountToRename),
Chris Wren717a8812017-03-31 15:34:39 -04001862 new UserHandle(accounts.userId));
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001863 synchronized(accounts.credentialsPermissionNotificationIds) {
1864 for (Pair<Pair<Account, String>, Integer> pair:
1865 accounts.credentialsPermissionNotificationIds.keySet()) {
1866 if (accountToRename.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04001867 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001868 cancelNotification(id, new UserHandle(accounts.userId));
1869 }
1870 }
1871 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001872 synchronized (accounts.dbLock) {
1873 synchronized (accounts.cacheLock) {
1874 accounts.accountsDb.beginTransaction();
1875 Account renamedAccount = new Account(newName, accountToRename.type);
1876 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1877 Log.e(TAG, "renameAccount failed - account with new name already exists");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001878 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001879 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001880 try {
1881 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
1882 if (accountId >= 0) {
1883 accounts.accountsDb.renameCeAccount(accountId, newName);
1884 if (accounts.accountsDb.renameDeAccount(
1885 accountId, newName, accountToRename.name)) {
1886 accounts.accountsDb.setTransactionSuccessful();
1887 } else {
1888 Log.e(TAG, "renameAccount failed");
1889 return null;
1890 }
1891 } else {
1892 Log.e(TAG, "renameAccount failed - old account does not exist");
1893 return null;
1894 }
1895 } finally {
1896 accounts.accountsDb.endTransaction();
1897 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001898 /*
1899 * Database transaction was successful. Clean up cached
1900 * data associated with the account in the user profile.
1901 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001902 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001903 /*
1904 * Extract the data and token caches before removing the
1905 * old account to preserve the user data associated with
1906 * the account.
1907 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001908 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1909 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
1910 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
1911 removeAccountFromCacheLocked(accounts, accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001912 /*
1913 * Update the cached data associated with the renamed
1914 * account.
1915 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001916 accounts.userDataCache.put(renamedAccount, tmpData);
1917 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1918 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
1919 accounts.previousNameCache.put(
1920 renamedAccount,
1921 new AtomicReference<>(accountToRename.name));
1922 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001923
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001924 int parentUserId = accounts.userId;
1925 if (canHaveProfile(parentUserId)) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001926 /*
1927 * Owner or system user account was renamed, rename the account for
1928 * those users with which the account was shared.
1929 */
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001930 List<UserInfo> users = getUserManager().getUsers(true);
1931 for (UserInfo user : users) {
1932 if (user.isRestricted()
1933 && (user.restrictedProfileParentId == parentUserId)) {
1934 renameSharedAccountAsUser(accountToRename, newName, user.id);
1935 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001936 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001937 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001938
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07001939 sendNotificationAccountUpdated(resultAccount, accounts);
1940 sendAccountsChangedBroadcast(accounts.userId);
1941 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001942 }
1943 return resultAccount;
1944 }
1945
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001946 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001947 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001948 return userInfo != null && userInfo.canHaveProfile();
1949 }
1950
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001951 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001952 public void removeAccount(IAccountManagerResponse response, Account account,
1953 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001954 removeAccountAsUser(
1955 response,
1956 account,
1957 expectActivityLaunch,
1958 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001959 }
1960
1961 @Override
1962 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001963 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001964 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001965 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1966 Log.v(TAG, "removeAccount: " + account
1967 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001968 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001969 + ", pid " + Binder.getCallingPid()
1970 + ", for user id " + userId);
1971 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001972 Preconditions.checkArgument(account != null, "account cannot be null");
1973 Preconditions.checkArgument(response != null, "response cannot be null");
1974
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001975 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001976 if (isCrossUser(callingUid, userId)) {
1977 throw new SecurityException(
1978 String.format(
1979 "User %s tying remove account for %s" ,
1980 UserHandle.getCallingUserId(),
1981 userId));
1982 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001983 /*
1984 * Only the system or authenticator should be allowed to remove accounts for that
1985 * authenticator. This will let users remove accounts (via Settings in the system) but not
1986 * arbitrary applications (like competing authenticators).
1987 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001988 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00001989 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1990 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001991 String msg = String.format(
1992 "uid %s cannot remove accounts of type: %s",
1993 callingUid,
1994 account.type);
1995 throw new SecurityException(msg);
1996 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001997 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001998 try {
1999 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2000 "User cannot modify accounts");
2001 } catch (RemoteException re) {
2002 }
2003 return;
2004 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002005 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002006 try {
2007 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2008 "User cannot modify accounts of this type (policy).");
2009 } catch (RemoteException re) {
2010 }
2011 return;
2012 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002013 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002014 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002015 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002016 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002017 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08002018 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002019 if (account.equals(pair.first.first)) {
Chris Wren717a8812017-03-31 15:34:39 -04002020 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002021 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08002022 }
2023 }
2024 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002025 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002026 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002027 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2028 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002029 accountId,
2030 accounts,
2031 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002032 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002033 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2034 } finally {
2035 restoreCallingIdentity(identityToken);
2036 }
2037 }
2038
2039 @Override
2040 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002041 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002042 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2043 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002044 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002045 + ", pid " + Binder.getCallingPid());
2046 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002047 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002048 if (account == null) {
2049 /*
2050 * Null accounts should result in returning false, as per
2051 * AccountManage.addAccountExplicitly(...) java doc.
2052 */
2053 Log.e(TAG, "account is null");
2054 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002055 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002056 String msg = String.format(
2057 "uid %s cannot explicitly add accounts of type: %s",
2058 callingUid,
2059 account.type);
2060 throw new SecurityException(msg);
2061 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002062 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002063 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002064 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002065 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2066 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002067 accountId,
2068 accounts,
2069 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002070 long identityToken = clearCallingIdentity();
2071 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002072 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002073 } finally {
2074 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002075 }
Fred Quintana60307342009-03-24 22:48:12 -07002076 }
2077
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002078 private class RemoveAccountSession extends Session {
2079 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002080 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002081 Account account, boolean expectActivityLaunch) {
2082 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002083 true /* stripAuthTokenFromResult */, account.name,
2084 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002085 mAccount = account;
2086 }
2087
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002088 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002089 protected String toDebugString(long now) {
2090 return super.toDebugString(now) + ", removeAccount"
2091 + ", account " + mAccount;
2092 }
2093
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002094 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002095 public void run() throws RemoteException {
2096 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2097 }
2098
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002099 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002100 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002101 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002102 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2103 && !result.containsKey(AccountManager.KEY_INTENT)) {
2104 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002105 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002106 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002107 }
2108 IAccountManagerResponse response = getResponseAndClose();
2109 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002110 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2111 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2112 + response);
2113 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002114 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002115 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002116 try {
2117 response.onResult(result2);
2118 } catch (RemoteException e) {
2119 // ignore
2120 }
2121 }
2122 }
2123 super.onResult(result);
2124 }
2125 }
2126
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002127 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002128 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002129 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002130 }
2131
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002132 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002133 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002134 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002135 if (!userUnlocked) {
2136 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2137 + " is still locked. CE data will be removed later");
2138 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002139 synchronized (accounts.dbLock) {
2140 synchronized (accounts.cacheLock) {
2141 Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
2142 accounts);
2143 accounts.accountsDb.beginTransaction();
2144 // Set to a dummy value, this will only be used if the database
2145 // transaction succeeds.
2146 long accountId = -1;
2147 try {
2148 accountId = accounts.accountsDb.findDeAccountId(account);
2149 if (accountId >= 0) {
2150 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002151 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002152 // always delete from CE table if CE storage is available
2153 // DE account could be removed while CE was locked
2154 if (userUnlocked) {
2155 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2156 if (ceAccountId >= 0) {
2157 accounts.accountsDb.deleteCeAccount(ceAccountId);
2158 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002159 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002160 accounts.accountsDb.setTransactionSuccessful();
2161 } finally {
2162 accounts.accountsDb.endTransaction();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002163 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002164 if (isChanged) {
2165 removeAccountFromCacheLocked(accounts, account);
2166 for (Entry<String, Integer> packageToVisibility : packagesToVisibility
2167 .entrySet()) {
2168 if (packageToVisibility.getValue()
2169 != AccountManager.VISIBILITY_NOT_VISIBLE) {
2170 notifyPackage(packageToVisibility.getKey(), accounts);
2171 }
2172 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002173
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002174 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
2175 sendAccountsChangedBroadcast(accounts.userId);
2176 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2177 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2178 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
2179 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002180 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002181 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002182 long id = Binder.clearCallingIdentity();
2183 try {
2184 int parentUserId = accounts.userId;
2185 if (canHaveProfile(parentUserId)) {
2186 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002187 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002188 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002189 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002190 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002191 }
2192 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002193 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002194 } finally {
2195 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002196 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002197
2198 if (isChanged) {
2199 synchronized (accounts.credentialsPermissionNotificationIds) {
2200 for (Pair<Pair<Account, String>, Integer> key
2201 : accounts.credentialsPermissionNotificationIds.keySet()) {
2202 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002203 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002204 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002205 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002206 account, uid, false));
2207 }
2208 }
2209 }
2210 }
2211
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002212 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002213 }
2214
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002215 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002216 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002217 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002218 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2219 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002220 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2221 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002222 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002223 + ", pid " + Binder.getCallingPid());
2224 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002225 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002226 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002227 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002228 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002229 List<Pair<Account, String>> deletedTokens;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002230 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002231 accounts.accountsDb.beginTransaction();
2232 try {
2233 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken);
2234 accounts.accountsDb.setTransactionSuccessful();
2235 } finally {
2236 accounts.accountsDb.endTransaction();
2237 }
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002238 synchronized (accounts.cacheLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002239 for (Pair<Account, String> tokenInfo : deletedTokens) {
2240 Account act = tokenInfo.first;
2241 String tokenType = tokenInfo.second;
2242 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null);
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002243 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002244 // wipe out cached token in memory.
2245 accounts.accountTokenCaches.remove(accountType, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002246 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002247 }
Fred Quintana60307342009-03-24 22:48:12 -07002248 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002249 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002250 }
2251 }
2252
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002253 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002254 String authToken) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002255 // TODO Move to AccountsDB
2256 List<Pair<Account, String>> results = new ArrayList<>();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002257 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002258
Fred Quintana33269202009-04-20 16:05:10 -07002259 try {
2260 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002261 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002262 String accountName = cursor.getString(1);
2263 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002264 accounts.accountsDb.deleteAuthToken(authTokenId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002265 results.add(Pair.create(new Account(accountName, accountType), authTokenType));
Fred Quintana60307342009-03-24 22:48:12 -07002266 }
Fred Quintana33269202009-04-20 16:05:10 -07002267 } finally {
2268 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002269 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002270 return results;
Fred Quintana60307342009-03-24 22:48:12 -07002271 }
2272
Carlos Valdivia91979be2015-05-22 14:11:35 -07002273 private void saveCachedToken(
2274 UserAccounts accounts,
2275 Account account,
2276 String callerPkg,
2277 byte[] callerSigDigest,
2278 String tokenType,
2279 String token,
2280 long expiryMillis) {
2281
2282 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2283 return;
2284 }
2285 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002286 UserHandle.of(accounts.userId));
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002287 synchronized (accounts.cacheLock) {
2288 accounts.accountTokenCaches.put(
2289 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002290 }
2291 }
2292
Amith Yamasani04e0d262012-02-14 11:50:53 -08002293 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2294 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002295 if (account == null || type == null) {
2296 return false;
2297 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002298 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002299 UserHandle.of(accounts.userId));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002300 synchronized (accounts.dbLock) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002301 accounts.accountsDb.beginTransaction();
2302 boolean updateCache = false;
2303 try {
2304 long accountId = accounts.accountsDb.findDeAccountId(account);
2305 if (accountId < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002306 return false;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07002307 }
2308 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2309 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2310 accounts.accountsDb.setTransactionSuccessful();
2311 updateCache = true;
2312 return true;
2313 }
2314 return false;
2315 } finally {
2316 accounts.accountsDb.endTransaction();
2317 if (updateCache) {
2318 synchronized (accounts.cacheLock) {
2319 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
2320 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002321 }
Fred Quintana33269202009-04-20 16:05:10 -07002322 }
Fred Quintana60307342009-03-24 22:48:12 -07002323 }
2324 }
2325
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002326 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002327 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002328 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002329 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2330 Log.v(TAG, "peekAuthToken: " + account
2331 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002332 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002333 + ", pid " + Binder.getCallingPid());
2334 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002335 Preconditions.checkNotNull(account, "account cannot be null");
2336 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002337 int userId = UserHandle.getCallingUserId();
2338 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002339 String msg = String.format(
2340 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2341 callingUid,
2342 account.type);
2343 throw new SecurityException(msg);
2344 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002345 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002346 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2347 + callingUid);
2348 return null;
2349 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002350 long identityToken = clearCallingIdentity();
2351 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002352 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002353 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002354 } finally {
2355 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002356 }
Fred Quintana60307342009-03-24 22:48:12 -07002357 }
2358
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002359 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002360 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002361 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002362 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2363 Log.v(TAG, "setAuthToken: " + account
2364 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002365 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002366 + ", pid " + Binder.getCallingPid());
2367 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002368 Preconditions.checkNotNull(account, "account cannot be null");
2369 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002370 int userId = UserHandle.getCallingUserId();
2371 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002372 String msg = String.format(
2373 "uid %s cannot set auth tokens associated with accounts of type: %s",
2374 callingUid,
2375 account.type);
2376 throw new SecurityException(msg);
2377 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002378 long identityToken = clearCallingIdentity();
2379 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002380 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002381 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002382 } finally {
2383 restoreCallingIdentity(identityToken);
2384 }
Fred Quintana60307342009-03-24 22:48:12 -07002385 }
2386
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002387 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002388 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002389 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002390 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2391 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002392 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002393 + ", pid " + Binder.getCallingPid());
2394 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002395 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002396 int userId = UserHandle.getCallingUserId();
2397 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002398 String msg = String.format(
2399 "uid %s cannot set secrets for accounts of type: %s",
2400 callingUid,
2401 account.type);
2402 throw new SecurityException(msg);
2403 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002404 long identityToken = clearCallingIdentity();
2405 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002406 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002407 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002408 } finally {
2409 restoreCallingIdentity(identityToken);
2410 }
Fred Quintana60307342009-03-24 22:48:12 -07002411 }
2412
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002413 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2414 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002415 if (account == null) {
2416 return;
2417 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002418 boolean isChanged = false;
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07002419 synchronized (accounts.dbLock) {
2420 synchronized (accounts.cacheLock) {
2421 accounts.accountsDb.beginTransaction();
2422 try {
2423 final long accountId = accounts.accountsDb.findDeAccountId(account);
2424 if (accountId >= 0) {
2425 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2426 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
2427 accounts.authTokenCache.remove(account);
2428 accounts.accountTokenCaches.remove(account);
2429 accounts.accountsDb.setTransactionSuccessful();
2430 // If there is an account whose password will be updated and the database
2431 // transactions succeed, then we say that a change has occured. Even if the
2432 // new password is the same as the old and there were no authtokens to
2433 // delete.
2434 isChanged = true;
2435 String action = (password == null || password.length() == 0) ?
2436 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2437 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2438 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts,
2439 callingUid);
2440 }
2441 } finally {
2442 accounts.accountsDb.endTransaction();
2443 if (isChanged) {
2444 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
2445 sendNotificationAccountUpdated(account, accounts);
2446 sendAccountsChangedBroadcast(accounts.userId);
2447 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002448 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002449 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002450 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002451 }
2452
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002453 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002454 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002455 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002456 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2457 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002458 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002459 + ", pid " + Binder.getCallingPid());
2460 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002461 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002462 int userId = UserHandle.getCallingUserId();
2463 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002464 String msg = String.format(
2465 "uid %s cannot clear passwords for accounts of type: %s",
2466 callingUid,
2467 account.type);
2468 throw new SecurityException(msg);
2469 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002470 long identityToken = clearCallingIdentity();
2471 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002472 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002473 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002474 } finally {
2475 restoreCallingIdentity(identityToken);
2476 }
Fred Quintana60307342009-03-24 22:48:12 -07002477 }
2478
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002479 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002480 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002481 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002482 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2483 Log.v(TAG, "setUserData: " + account
2484 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002485 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002486 + ", pid " + Binder.getCallingPid());
2487 }
Fred Quintana382601f2010-03-25 12:25:10 -07002488 if (key == null) throw new IllegalArgumentException("key is null");
2489 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002490 int userId = UserHandle.getCallingUserId();
2491 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002492 String msg = String.format(
2493 "uid %s cannot set user data for accounts of type: %s",
2494 callingUid,
2495 account.type);
2496 throw new SecurityException(msg);
2497 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002498 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002499 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002500 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002501 if (!accountExistsCache(accounts, account)) {
2502 return;
Simranjit Kohli858511c2016-03-10 18:36:11 +00002503 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002504 setUserdataInternal(accounts, account, key, value);
Fred Quintana60307342009-03-24 22:48:12 -07002505 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002506 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002507 }
2508 }
2509
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002510 private boolean accountExistsCache(UserAccounts accounts, Account account) {
2511 synchronized (accounts.cacheLock) {
2512 if (accounts.accountCache.containsKey(account.type)) {
2513 for (Account acc : accounts.accountCache.get(account.type)) {
2514 if (acc.name.equals(account.name)) {
2515 return true;
2516 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00002517 }
2518 }
2519 }
2520 return false;
2521 }
2522
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002523 private void setUserdataInternal(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002524 String value) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002525 synchronized (accounts.dbLock) {
2526 accounts.accountsDb.beginTransaction();
2527 try {
2528 long accountId = accounts.accountsDb.findDeAccountId(account);
2529 if (accountId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002530 return;
2531 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002532 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
2533 if (extrasId < 0) {
2534 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
2535 if (extrasId < 0) {
2536 return;
2537 }
2538 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
2539 return;
2540 }
2541 accounts.accountsDb.setTransactionSuccessful();
2542 } finally {
2543 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002544 }
Fyodor Kupolov3d734992017-03-29 17:28:52 -07002545 synchronized (accounts.cacheLock) {
2546 writeUserDataIntoCacheLocked(accounts, account, key, value);
2547 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002548 }
2549 }
2550
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002551 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002552 if (result == null) {
2553 Log.e(TAG, "the result is unexpectedly null", new Exception());
2554 }
2555 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2556 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2557 + response);
2558 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002559 try {
2560 response.onResult(result);
2561 } catch (RemoteException e) {
2562 // if the caller is dead then there is no one to care about remote
2563 // exceptions
2564 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2565 Log.v(TAG, "failure while notifying response", e);
2566 }
2567 }
2568 }
2569
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002570 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002571 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2572 final String authTokenType)
2573 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002574 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2575 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002576
Fred Quintanad9640ec2012-05-23 12:37:00 -07002577 final int callingUid = getCallingUid();
2578 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002579 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002580 throw new SecurityException("can only call from system");
2581 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002582 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002583 long identityToken = clearCallingIdentity();
2584 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002585 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002586 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2587 false /* stripAuthTokenFromResult */, null /* accountName */,
2588 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002589 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002590 protected String toDebugString(long now) {
2591 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002592 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002593 + ", authTokenType " + authTokenType;
2594 }
2595
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002596 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002597 public void run() throws RemoteException {
2598 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2599 }
2600
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002601 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002602 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002603 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002604 if (result != null) {
2605 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2606 Bundle bundle = new Bundle();
2607 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2608 super.onResult(bundle);
2609 return;
2610 } else {
2611 super.onResult(result);
2612 }
2613 }
2614 }.bind();
2615 } finally {
2616 restoreCallingIdentity(identityToken);
2617 }
2618 }
2619
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002620 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002621 public void getAuthToken(
2622 IAccountManagerResponse response,
2623 final Account account,
2624 final String authTokenType,
2625 final boolean notifyOnAuthFailure,
2626 final boolean expectActivityLaunch,
2627 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002628 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002629 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2630 Log.v(TAG, "getAuthToken: " + account
2631 + ", response " + response
2632 + ", authTokenType " + authTokenType
2633 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2634 + ", expectActivityLaunch " + expectActivityLaunch
2635 + ", caller's uid " + Binder.getCallingUid()
2636 + ", pid " + Binder.getCallingPid());
2637 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002638 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002639 try {
2640 if (account == null) {
2641 Slog.w(TAG, "getAuthToken called with null account");
2642 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2643 return;
2644 }
2645 if (authTokenType == null) {
2646 Slog.w(TAG, "getAuthToken called with null authTokenType");
2647 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2648 return;
2649 }
2650 } catch (RemoteException e) {
2651 Slog.w(TAG, "Failed to report error back to the client." + e);
2652 return;
2653 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002654 int userId = UserHandle.getCallingUserId();
2655 long ident = Binder.clearCallingIdentity();
2656 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002657 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002658 try {
2659 accounts = getUserAccounts(userId);
2660 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2661 AuthenticatorDescription.newKey(account.type), accounts.userId);
2662 } finally {
2663 Binder.restoreCallingIdentity(ident);
2664 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002665
Costin Manolachea40c6302010-12-13 14:50:45 -08002666 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002667 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002668
2669 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002670 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002671 final boolean permissionGranted =
2672 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002673
Carlos Valdivia91979be2015-05-22 14:11:35 -07002674 // Get the calling package. We will use it for the purpose of caching.
2675 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002676 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002677 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002678 try {
2679 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2680 } finally {
2681 Binder.restoreCallingIdentity(ident);
2682 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002683 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2684 String msg = String.format(
2685 "Uid %s is attempting to illegally masquerade as package %s!",
2686 callerUid,
2687 callerPkg);
2688 throw new SecurityException(msg);
2689 }
2690
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002691 // let authenticator know the identity of the caller
2692 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2693 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002694
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002695 if (notifyOnAuthFailure) {
2696 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002697 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002698
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002699 long identityToken = clearCallingIdentity();
2700 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002701 // Distill the caller's package signatures into a single digest.
2702 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2703
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002704 // if the caller has permission, do the peek. otherwise go the more expensive
2705 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002706 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002707 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002708 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002709 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002710 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2711 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2712 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002713 onResult(response, result);
2714 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002715 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002716 }
2717
Carlos Valdivia91979be2015-05-22 14:11:35 -07002718 if (customTokens) {
2719 /*
2720 * Look up tokens in the new cache only if the loginOptions don't have parameters
2721 * outside of those expected to be injected by the AccountManager, e.g.
2722 * ANDORID_PACKAGE_NAME.
2723 */
2724 String token = readCachedTokenInternal(
2725 accounts,
2726 account,
2727 authTokenType,
2728 callerPkg,
2729 callerPkgSigDigest);
2730 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002731 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2732 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2733 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002734 Bundle result = new Bundle();
2735 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2736 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2737 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2738 onResult(response, result);
2739 return;
2740 }
2741 }
2742
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002743 new Session(
2744 accounts,
2745 response,
2746 account.type,
2747 expectActivityLaunch,
2748 false /* stripAuthTokenFromResult */,
2749 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002750 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002751 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002752 protected String toDebugString(long now) {
2753 if (loginOptions != null) loginOptions.keySet();
2754 return super.toDebugString(now) + ", getAuthToken"
2755 + ", " + account
2756 + ", authTokenType " + authTokenType
2757 + ", loginOptions " + loginOptions
2758 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2759 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002760
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002761 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002762 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002763 // If the caller doesn't have permission then create and return the
2764 // "grant permission" intent instead of the "getAuthToken" intent.
2765 if (!permissionGranted) {
2766 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2767 } else {
2768 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2769 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002770 }
2771
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002772 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002773 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002774 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002775 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002776 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002777 Intent intent = newGrantCredentialsPermissionIntent(
2778 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002779 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002780 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002781 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002782 authTokenType,
2783 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002784 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002785 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002786 onResult(bundle);
2787 return;
2788 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002789 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002790 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002791 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2792 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002793 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002794 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002795 "the type and name should not be empty");
2796 return;
2797 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002798 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002799 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002800 saveAuthTokenToDatabase(
2801 mAccounts,
2802 resultAccount,
2803 authTokenType,
2804 authToken);
2805 }
2806 long expiryMillis = result.getLong(
2807 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2808 if (customTokens
2809 && expiryMillis > System.currentTimeMillis()) {
2810 saveCachedToken(
2811 mAccounts,
2812 account,
2813 callerPkg,
2814 callerPkgSigDigest,
2815 authTokenType,
2816 authToken,
2817 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002818 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002819 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002820
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002821 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002822 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002823 /*
2824 * Make sure that the supplied intent is owned by the authenticator
2825 * giving it to the system. Otherwise a malicious authenticator could
2826 * have users launching arbitrary activities by tricking users to
2827 * interact with malicious notifications.
2828 */
2829 checkKeyIntent(
2830 Binder.getCallingUid(),
2831 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002832 doNotification(
2833 mAccounts,
2834 account,
2835 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002836 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002837 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002838 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002839 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002840 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002841 }.bind();
2842 } finally {
2843 restoreCallingIdentity(identityToken);
2844 }
Fred Quintana60307342009-03-24 22:48:12 -07002845 }
2846
Carlos Valdivia91979be2015-05-22 14:11:35 -07002847 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2848 MessageDigest digester;
2849 try {
2850 digester = MessageDigest.getInstance("SHA-256");
2851 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2852 callerPkg, PackageManager.GET_SIGNATURES);
2853 for (Signature sig : pkgInfo.signatures) {
2854 digester.update(sig.toByteArray());
2855 }
2856 } catch (NoSuchAlgorithmException x) {
2857 Log.wtf(TAG, "SHA-256 should be available", x);
2858 digester = null;
2859 } catch (NameNotFoundException e) {
2860 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2861 digester = null;
2862 }
2863 return (digester == null) ? null : digester.digest();
2864 }
2865
Dianne Hackborn41203752012-08-31 14:05:51 -07002866 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002867 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002868 int uid = intent.getIntExtra(
2869 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2870 String authTokenType = intent.getStringExtra(
2871 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002872 final String titleAndSubtitle =
2873 mContext.getString(R.string.permission_request_notification_with_subtitle,
2874 account.name);
2875 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002876 String title = titleAndSubtitle;
2877 String subtitle = "";
2878 if (index > 0) {
2879 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002880 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002881 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002882 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002883 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05002884 Notification n =
2885 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
2886 .setSmallIcon(android.R.drawable.stat_sys_warning)
2887 .setWhen(0)
2888 .setColor(contextForUser.getColor(
2889 com.android.internal.R.color.system_notification_accent_color))
2890 .setContentTitle(title)
2891 .setContentText(subtitle)
2892 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2893 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2894 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002895 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002896 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002897 }
2898
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002899 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2900 int uid, AccountAuthenticatorResponse response, String authTokenType,
2901 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002902
2903 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002904
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002905 if (startInNewTask) {
2906 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2907 // Since it was set in Eclair+ we can't change it without breaking apps using
2908 // the intent from a non-Activity context. This is the default behavior.
2909 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2910 }
Chris Wren717a8812017-03-31 15:34:39 -04002911 intent.addCategory(getCredentialPermissionNotificationId(account,
2912 authTokenType, uid).mTag + (packageName != null ? packageName : ""));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002913 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002914 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2915 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002916 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002917
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002918 return intent;
2919 }
2920
Chris Wren717a8812017-03-31 15:34:39 -04002921 private NotificationId getCredentialPermissionNotificationId(Account account,
2922 String authTokenType, int uid) {
2923 NotificationId nId;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002924 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002925 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002926 final Pair<Pair<Account, String>, Integer> key =
2927 new Pair<Pair<Account, String>, Integer>(
2928 new Pair<Account, String>(account, authTokenType), uid);
Chris Wren717a8812017-03-31 15:34:39 -04002929 nId = accounts.credentialsPermissionNotificationIds.get(key);
2930 if (nId == null) {
2931 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
2932 + ":" + account.hashCode() + ":" + authTokenType.hashCode();
2933 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
2934 nId = new NotificationId(tag, id);
2935 accounts.credentialsPermissionNotificationIds.put(key, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002936 }
2937 }
Chris Wren717a8812017-03-31 15:34:39 -04002938 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002939 }
2940
Chris Wren717a8812017-03-31 15:34:39 -04002941 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
2942 NotificationId nId;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002943 synchronized (accounts.signinRequiredNotificationIds) {
Chris Wren717a8812017-03-31 15:34:39 -04002944 nId = accounts.signinRequiredNotificationIds.get(account);
2945 if (nId == null) {
2946 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
2947 + ":" + account.hashCode();
2948 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
2949 nId = new NotificationId(tag, id);
2950 accounts.signinRequiredNotificationIds.put(account, nId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002951 }
2952 }
Chris Wren717a8812017-03-31 15:34:39 -04002953 return nId;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002954 }
2955
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002956 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002957 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002958 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002959 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002960 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002961 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2962 Log.v(TAG, "addAccount: accountType " + accountType
2963 + ", response " + response
2964 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002965 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002966 + ", expectActivityLaunch " + expectActivityLaunch
2967 + ", caller's uid " + Binder.getCallingUid()
2968 + ", pid " + Binder.getCallingPid());
2969 }
Fred Quintana382601f2010-03-25 12:25:10 -07002970 if (response == null) throw new IllegalArgumentException("response is null");
2971 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002972
Amith Yamasani71e6c692013-03-24 17:39:28 -07002973 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002974 final int uid = Binder.getCallingUid();
2975 final int userId = UserHandle.getUserId(uid);
2976 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002977 try {
2978 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2979 "User is not allowed to add an account!");
2980 } catch (RemoteException re) {
2981 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002982 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002983 return;
2984 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002985 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002986 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002987 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2988 "User cannot modify accounts of this type (policy).");
2989 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002990 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002991 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2992 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002993 return;
2994 }
2995
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002996 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002997 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2998 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2999 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3000
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003001 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003002 long identityToken = clearCallingIdentity();
3003 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003004 UserAccounts accounts = getUserAccounts(usrId);
3005 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003006 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3007 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003008 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003009 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003010 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003011 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003012 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07003013 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07003014 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003015 }
Fred Quintanaa698f422009-04-08 19:14:54 -07003016
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003017 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003018 protected String toDebugString(long now) {
3019 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07003020 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003021 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003022 }
3023 }.bind();
3024 } finally {
3025 restoreCallingIdentity(identityToken);
3026 }
Fred Quintana60307342009-03-24 22:48:12 -07003027 }
3028
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003029 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003030 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
3031 final String authTokenType, final String[] requiredFeatures,
3032 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003033 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003034 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003035 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3036 Log.v(TAG, "addAccount: accountType " + accountType
3037 + ", response " + response
3038 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003039 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003040 + ", expectActivityLaunch " + expectActivityLaunch
3041 + ", caller's uid " + Binder.getCallingUid()
3042 + ", pid " + Binder.getCallingPid()
3043 + ", for user id " + userId);
3044 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003045 Preconditions.checkArgument(response != null, "response cannot be null");
3046 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003047 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003048 if (isCrossUser(callingUid, userId)) {
3049 throw new SecurityException(
3050 String.format(
3051 "User %s trying to add account for %s" ,
3052 UserHandle.getCallingUserId(),
3053 userId));
3054 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003055
3056 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003057 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003058 try {
3059 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3060 "User is not allowed to add an account!");
3061 } catch (RemoteException re) {
3062 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003063 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003064 return;
3065 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003066 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003067 try {
3068 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3069 "User cannot modify accounts of this type (policy).");
3070 } catch (RemoteException re) {
3071 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003072 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3073 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003074 return;
3075 }
3076
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003077 final int pid = Binder.getCallingPid();
3078 final int uid = Binder.getCallingUid();
3079 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3080 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3081 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3082
3083 long identityToken = clearCallingIdentity();
3084 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003085 UserAccounts accounts = getUserAccounts(userId);
3086 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003087 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3088 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003089 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003090 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003091 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003092 @Override
3093 public void run() throws RemoteException {
3094 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3095 options);
3096 }
3097
3098 @Override
3099 protected String toDebugString(long now) {
3100 return super.toDebugString(now) + ", addAccount"
3101 + ", accountType " + accountType
3102 + ", requiredFeatures "
3103 + (requiredFeatures != null
3104 ? TextUtils.join(",", requiredFeatures)
3105 : null);
3106 }
3107 }.bind();
3108 } finally {
3109 restoreCallingIdentity(identityToken);
3110 }
3111 }
3112
Sandra Kwan78812282015-11-04 11:19:47 -08003113 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003114 public void startAddAccountSession(
3115 final IAccountManagerResponse response,
3116 final String accountType,
3117 final String authTokenType,
3118 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003119 final boolean expectActivityLaunch,
3120 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003121 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003122 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3123 Log.v(TAG,
3124 "startAddAccountSession: accountType " + accountType
3125 + ", response " + response
3126 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003127 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003128 + ", expectActivityLaunch " + expectActivityLaunch
3129 + ", caller's uid " + Binder.getCallingUid()
3130 + ", pid " + Binder.getCallingPid());
3131 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003132 Preconditions.checkArgument(response != null, "response cannot be null");
3133 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003134
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003135 final int uid = Binder.getCallingUid();
3136 final int userId = UserHandle.getUserId(uid);
3137 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003138 try {
3139 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3140 "User is not allowed to add an account!");
3141 } catch (RemoteException re) {
3142 }
3143 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3144 return;
3145 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003146 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003147 try {
3148 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3149 "User cannot modify accounts of this type (policy).");
3150 } catch (RemoteException re) {
3151 }
3152 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3153 userId);
3154 return;
3155 }
Sandra Kwan78812282015-11-04 11:19:47 -08003156 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003157 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3158 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3159 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3160
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003161 // Check to see if the Password should be included to the caller.
3162 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3163 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003164 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003165
Sandra Kwan78812282015-11-04 11:19:47 -08003166 long identityToken = clearCallingIdentity();
3167 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003168 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003169 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3170 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003171 new StartAccountSession(
3172 accounts,
3173 response,
3174 accountType,
3175 expectActivityLaunch,
3176 null /* accountName */,
3177 false /* authDetailsRequired */,
3178 true /* updateLastAuthenticationTime */,
3179 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003180 @Override
3181 public void run() throws RemoteException {
3182 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3183 requiredFeatures, options);
3184 }
3185
3186 @Override
3187 protected String toDebugString(long now) {
3188 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3189 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3190 + accountType + ", requiredFeatures "
3191 + (requiredFeatures != null ? requiredFeaturesStr : null);
3192 }
3193 }.bind();
3194 } finally {
3195 restoreCallingIdentity(identityToken);
3196 }
3197 }
3198
3199 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3200 private abstract class StartAccountSession extends Session {
3201
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003202 private final boolean mIsPasswordForwardingAllowed;
3203
3204 public StartAccountSession(
3205 UserAccounts accounts,
3206 IAccountManagerResponse response,
3207 String accountType,
3208 boolean expectActivityLaunch,
3209 String accountName,
3210 boolean authDetailsRequired,
3211 boolean updateLastAuthenticationTime,
3212 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003213 super(accounts, response, accountType, expectActivityLaunch,
3214 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3215 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003216 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003217 }
3218
3219 @Override
3220 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003221 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003222 mNumResults++;
3223 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003224 if (result != null
3225 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003226 checkKeyIntent(
3227 Binder.getCallingUid(),
3228 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003229 }
Sandra Kwan78812282015-11-04 11:19:47 -08003230 IAccountManagerResponse response;
3231 if (mExpectActivityLaunch && result != null
3232 && result.containsKey(AccountManager.KEY_INTENT)) {
3233 response = mResponse;
3234 } else {
3235 response = getResponseAndClose();
3236 }
3237 if (response == null) {
3238 return;
3239 }
3240 if (result == null) {
3241 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3242 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3243 + response);
3244 }
3245 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3246 "null bundle returned");
3247 return;
3248 }
3249
3250 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3251 // All AccountManager error codes are greater
3252 // than 0
3253 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3254 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3255 return;
3256 }
3257
Hongming Jin368aa192016-07-29 14:29:54 -07003258 // Omit passwords if the caller isn't permitted to see them.
3259 if (!mIsPasswordForwardingAllowed) {
3260 result.remove(AccountManager.KEY_PASSWORD);
3261 }
3262
Sandra Kwan78812282015-11-04 11:19:47 -08003263 // Strip auth token from result.
3264 result.remove(AccountManager.KEY_AUTHTOKEN);
3265
3266 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3267 Log.v(TAG,
3268 getClass().getSimpleName() + " calling onResult() on response " + response);
3269 }
3270
3271 // Get the session bundle created by authenticator. The
3272 // bundle contains data necessary for finishing the session
3273 // later. The session bundle will be encrypted here and
3274 // decrypted later when trying to finish the session.
3275 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3276 if (sessionBundle != null) {
3277 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3278 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003279 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003280 Log.w(TAG, "Account type in session bundle doesn't match request.");
3281 }
3282 // Add accountType info to session bundle. This will
3283 // override any value set by authenticator.
3284 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3285
3286 // Encrypt session bundle before returning to caller.
3287 try {
3288 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3289 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3290 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3291 } catch (GeneralSecurityException e) {
3292 if (Log.isLoggable(TAG, Log.DEBUG)) {
3293 Log.v(TAG, "Failed to encrypt session bundle!", e);
3294 }
3295 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3296 "failed to encrypt session bundle");
3297 return;
3298 }
3299 }
3300
3301 sendResponse(response, result);
3302 }
3303 }
3304
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003305 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003306 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003307 @NonNull Bundle sessionBundle,
3308 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003309 Bundle appInfo,
3310 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003311 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003312 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003313 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3314 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003315 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003316 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003317 + ", caller's uid " + callingUid
3318 + ", caller's user id " + UserHandle.getCallingUserId()
3319 + ", pid " + Binder.getCallingPid()
3320 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003321 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003322 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003323 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3324 // Account type is added to it before encryption.
3325 if (sessionBundle == null || sessionBundle.size() == 0) {
3326 throw new IllegalArgumentException("sessionBundle is empty");
3327 }
3328
Dmitry Dementyev52745472016-12-02 10:27:45 -08003329 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003330 if (isCrossUser(callingUid, userId)) {
3331 throw new SecurityException(
3332 String.format(
3333 "User %s trying to finish session for %s without cross user permission",
3334 UserHandle.getCallingUserId(),
3335 userId));
3336 }
3337
Sandra Kwan0b84b452016-01-20 15:25:42 -08003338 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003339 sendErrorResponse(response,
3340 AccountManager.ERROR_CODE_USER_RESTRICTED,
3341 "User is not allowed to add an account!");
3342 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3343 return;
3344 }
3345
3346 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003347 final Bundle decryptedBundle;
3348 final String accountType;
3349 // First decrypt session bundle to get account type for checking permission.
3350 try {
3351 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3352 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3353 if (decryptedBundle == null) {
3354 sendErrorResponse(
3355 response,
3356 AccountManager.ERROR_CODE_BAD_REQUEST,
3357 "failed to decrypt session bundle");
3358 return;
3359 }
3360 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3361 // Account type cannot be null. This should not happen if session bundle was created
3362 // properly by #StartAccountSession.
3363 if (TextUtils.isEmpty(accountType)) {
3364 sendErrorResponse(
3365 response,
3366 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3367 "accountType is empty");
3368 return;
3369 }
3370
3371 // If by any chances, decryptedBundle contains colliding keys with
3372 // system info
3373 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3374 // update credentials flow, we should replace with the new values of the current call.
3375 if (appInfo != null) {
3376 decryptedBundle.putAll(appInfo);
3377 }
3378
3379 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003380 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003381 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3382 } catch (GeneralSecurityException e) {
3383 if (Log.isLoggable(TAG, Log.DEBUG)) {
3384 Log.v(TAG, "Failed to decrypt session bundle!", e);
3385 }
3386 sendErrorResponse(
3387 response,
3388 AccountManager.ERROR_CODE_BAD_REQUEST,
3389 "failed to decrypt session bundle");
3390 return;
3391 }
3392
Sandra Kwan0b84b452016-01-20 15:25:42 -08003393 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003394 sendErrorResponse(
3395 response,
3396 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3397 "User cannot modify accounts of this type (policy).");
3398 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3399 userId);
3400 return;
3401 }
3402
3403 long identityToken = clearCallingIdentity();
3404 try {
3405 UserAccounts accounts = getUserAccounts(userId);
3406 logRecordWithUid(
3407 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003408 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3409 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003410 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003411 new Session(
3412 accounts,
3413 response,
3414 accountType,
3415 expectActivityLaunch,
3416 true /* stripAuthTokenFromResult */,
3417 null /* accountName */,
3418 false /* authDetailsRequired */,
3419 true /* updateLastAuthenticationTime */) {
3420 @Override
3421 public void run() throws RemoteException {
3422 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3423 }
3424
3425 @Override
3426 protected String toDebugString(long now) {
3427 return super.toDebugString(now)
3428 + ", finishSession"
3429 + ", accountType " + accountType;
3430 }
3431 }.bind();
3432 } finally {
3433 restoreCallingIdentity(identityToken);
3434 }
3435 }
3436
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003437 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003438 final DevicePolicyManagerInternal dpmi =
3439 LocalServices.getService(DevicePolicyManagerInternal.class);
3440 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003441 if (dpmi == null) {
3442 intent = getDefaultCantAddAccountIntent(errorCode);
3443 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003444 intent = dpmi.createUserRestrictionSupportIntent(userId,
3445 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3446 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3447 intent = dpmi.createShowAdminSupportIntent(userId, false);
3448 }
3449 if (intent == null) {
3450 intent = getDefaultCantAddAccountIntent(errorCode);
3451 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003452 long identityToken = clearCallingIdentity();
3453 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003454 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003455 } finally {
3456 restoreCallingIdentity(identityToken);
3457 }
3458 }
3459
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003460 /**
3461 * Called when we don't know precisely who is preventing us from adding an account.
3462 */
3463 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3464 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3465 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3466 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3467 return cantAddAccount;
3468 }
3469
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003470 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003471 public void confirmCredentialsAsUser(
3472 IAccountManagerResponse response,
3473 final Account account,
3474 final Bundle options,
3475 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003476 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003477 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003478 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003479 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3480 Log.v(TAG, "confirmCredentials: " + account
3481 + ", response " + response
3482 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003483 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003484 + ", pid " + Binder.getCallingPid());
3485 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003486 // Only allow the system process to read accounts of other users
3487 if (isCrossUser(callingUid, userId)) {
3488 throw new SecurityException(
3489 String.format(
3490 "User %s trying to confirm account credentials for %s" ,
3491 UserHandle.getCallingUserId(),
3492 userId));
3493 }
Fred Quintana382601f2010-03-25 12:25:10 -07003494 if (response == null) throw new IllegalArgumentException("response is null");
3495 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003496 long identityToken = clearCallingIdentity();
3497 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003498 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003499 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003500 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003501 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003502 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003503 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003504 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003505 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003506 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003507 protected String toDebugString(long now) {
3508 return super.toDebugString(now) + ", confirmCredentials"
3509 + ", " + account;
3510 }
3511 }.bind();
3512 } finally {
3513 restoreCallingIdentity(identityToken);
3514 }
Fred Quintana60307342009-03-24 22:48:12 -07003515 }
3516
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003517 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003518 public void updateCredentials(IAccountManagerResponse response, final Account account,
3519 final String authTokenType, final boolean expectActivityLaunch,
3520 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003521 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003522 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3523 Log.v(TAG, "updateCredentials: " + account
3524 + ", response " + response
3525 + ", authTokenType " + authTokenType
3526 + ", expectActivityLaunch " + expectActivityLaunch
3527 + ", caller's uid " + Binder.getCallingUid()
3528 + ", pid " + Binder.getCallingPid());
3529 }
Fred Quintana382601f2010-03-25 12:25:10 -07003530 if (response == null) throw new IllegalArgumentException("response is null");
3531 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003532 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003533 long identityToken = clearCallingIdentity();
3534 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003535 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003536 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003537 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003538 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003539 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003540 public void run() throws RemoteException {
3541 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3542 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003543 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003544 protected String toDebugString(long now) {
3545 if (loginOptions != null) loginOptions.keySet();
3546 return super.toDebugString(now) + ", updateCredentials"
3547 + ", " + account
3548 + ", authTokenType " + authTokenType
3549 + ", loginOptions " + loginOptions;
3550 }
3551 }.bind();
3552 } finally {
3553 restoreCallingIdentity(identityToken);
3554 }
Fred Quintana60307342009-03-24 22:48:12 -07003555 }
3556
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003557 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003558 public void startUpdateCredentialsSession(
3559 IAccountManagerResponse response,
3560 final Account account,
3561 final String authTokenType,
3562 final boolean expectActivityLaunch,
3563 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003564 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003565 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3566 Log.v(TAG,
3567 "startUpdateCredentialsSession: " + account + ", response " + response
3568 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3569 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3570 + ", pid " + Binder.getCallingPid());
3571 }
3572 if (response == null) {
3573 throw new IllegalArgumentException("response is null");
3574 }
3575 if (account == null) {
3576 throw new IllegalArgumentException("account is null");
3577 }
Sandra Kwana578d112015-12-16 16:01:43 -08003578
3579 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003580 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003581
3582 // Check to see if the Password should be included to the caller.
3583 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3584 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003585 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003586
Sandra Kwane68c37e2015-11-12 17:11:49 -08003587 long identityToken = clearCallingIdentity();
3588 try {
3589 UserAccounts accounts = getUserAccounts(userId);
3590 new StartAccountSession(
3591 accounts,
3592 response,
3593 account.type,
3594 expectActivityLaunch,
3595 account.name,
3596 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003597 true /* updateLastCredentialTime */,
3598 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003599 @Override
3600 public void run() throws RemoteException {
3601 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3602 loginOptions);
3603 }
3604
3605 @Override
3606 protected String toDebugString(long now) {
3607 if (loginOptions != null)
3608 loginOptions.keySet();
3609 return super.toDebugString(now)
3610 + ", startUpdateCredentialsSession"
3611 + ", " + account
3612 + ", authTokenType " + authTokenType
3613 + ", loginOptions " + loginOptions;
3614 }
3615 }.bind();
3616 } finally {
3617 restoreCallingIdentity(identityToken);
3618 }
3619 }
3620
3621 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003622 public void isCredentialsUpdateSuggested(
3623 IAccountManagerResponse response,
3624 final Account account,
3625 final String statusToken) {
3626 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3627 Log.v(TAG,
3628 "isCredentialsUpdateSuggested: " + account + ", response " + response
3629 + ", caller's uid " + Binder.getCallingUid()
3630 + ", pid " + Binder.getCallingPid());
3631 }
3632 if (response == null) {
3633 throw new IllegalArgumentException("response is null");
3634 }
3635 if (account == null) {
3636 throw new IllegalArgumentException("account is null");
3637 }
3638 if (TextUtils.isEmpty(statusToken)) {
3639 throw new IllegalArgumentException("status token is empty");
3640 }
3641
Sandra Kwan390c9d22016-01-12 14:13:37 -08003642 int usrId = UserHandle.getCallingUserId();
3643 long identityToken = clearCallingIdentity();
3644 try {
3645 UserAccounts accounts = getUserAccounts(usrId);
3646 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3647 false /* stripAuthTokenFromResult */, account.name,
3648 false /* authDetailsRequired */) {
3649 @Override
3650 protected String toDebugString(long now) {
3651 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3652 + ", " + account;
3653 }
3654
3655 @Override
3656 public void run() throws RemoteException {
3657 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3658 }
3659
3660 @Override
3661 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003662 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003663 IAccountManagerResponse response = getResponseAndClose();
3664 if (response == null) {
3665 return;
3666 }
3667
3668 if (result == null) {
3669 sendErrorResponse(
3670 response,
3671 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3672 "null bundle");
3673 return;
3674 }
3675
3676 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3677 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3678 + response);
3679 }
3680 // Check to see if an error occurred. We know if an error occurred because all
3681 // error codes are greater than 0.
3682 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3683 sendErrorResponse(response,
3684 result.getInt(AccountManager.KEY_ERROR_CODE),
3685 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3686 return;
3687 }
3688 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3689 sendErrorResponse(
3690 response,
3691 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3692 "no result in response");
3693 return;
3694 }
3695 final Bundle newResult = new Bundle();
3696 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3697 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3698 sendResponse(response, newResult);
3699 }
3700 }.bind();
3701 } finally {
3702 restoreCallingIdentity(identityToken);
3703 }
3704 }
3705
3706 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003707 public void editProperties(IAccountManagerResponse response, final String accountType,
3708 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003709 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003710 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3711 Log.v(TAG, "editProperties: accountType " + accountType
3712 + ", response " + response
3713 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003714 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003715 + ", pid " + Binder.getCallingPid());
3716 }
Fred Quintana382601f2010-03-25 12:25:10 -07003717 if (response == null) throw new IllegalArgumentException("response is null");
3718 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003719 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003720 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3721 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003722 String msg = String.format(
3723 "uid %s cannot edit authenticator properites for account type: %s",
3724 callingUid,
3725 accountType);
3726 throw new SecurityException(msg);
3727 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003728 long identityToken = clearCallingIdentity();
3729 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003730 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003731 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003732 true /* stripAuthTokenFromResult */, null /* accountName */,
3733 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003734 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003735 public void run() throws RemoteException {
3736 mAuthenticator.editProperties(this, mAccountType);
3737 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003738 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003739 protected String toDebugString(long now) {
3740 return super.toDebugString(now) + ", editProperties"
3741 + ", accountType " + accountType;
3742 }
3743 }.bind();
3744 } finally {
3745 restoreCallingIdentity(identityToken);
3746 }
Fred Quintana60307342009-03-24 22:48:12 -07003747 }
3748
Amith Yamasani12747872015-12-07 14:19:49 -08003749 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003750 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3751 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003752 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003753 throw new SecurityException("Can be called only by system UID");
3754 }
3755 Preconditions.checkNotNull(account, "account cannot be null");
3756 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3757 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3758
3759 final int userId = userHandle.getIdentifier();
3760
3761 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3762
3763 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003764 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003765 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003766 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003767 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003768 return false;
3769 }
3770 }
3771
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003772 // Returns package with oldest target SDK for given UID.
3773 private String getPackageNameForUid(int uid) {
3774 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3775 if (ArrayUtils.isEmpty(packageNames)) {
3776 return null;
3777 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003778 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003779 if (packageNames.length == 1) {
3780 return packageName;
3781 }
3782 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003783 int oldestVersion = Integer.MAX_VALUE;
3784 for (String name : packageNames) {
3785 try {
3786 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3787 if (applicationInfo != null) {
3788 int version = applicationInfo.targetSdkVersion;
3789 if (version < oldestVersion) {
3790 oldestVersion = version;
3791 packageName = name;
3792 }
3793 }
3794 } catch (NameNotFoundException e) {
3795 // skip
3796 }
3797 }
3798 return packageName;
3799 }
3800
Svet Ganovf6d424f12016-09-20 20:18:53 -07003801 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3802 int uid) {
3803 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003804 packageName = getPackageNameForUid(uid);
3805 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003806 return false;
3807 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003808 }
3809
3810 // Use null token which means any token. Having a token means the package
3811 // is trusted by the authenticator, hence it is fine to access the account.
3812 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3813 return true;
3814 }
3815 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003816 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003817
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003818 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003819 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003820 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003821 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003822 }
3823
3824 @Override
3825 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3826 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003827 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003828 throw new SecurityException("Can be called only by system UID");
3829 }
3830
3831 Preconditions.checkNotNull(account, "account cannot be null");
3832 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3833 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3834
3835 final int userId = userHandle.getIdentifier();
3836
3837 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3838
3839 final int uid;
3840 try {
3841 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3842 } catch (NameNotFoundException e) {
3843 Slog.e(TAG, "Unknown package " + packageName);
3844 return null;
3845 }
3846
3847 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3848
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003849 final long identity = Binder.clearCallingIdentity();
3850 try {
3851 return PendingIntent.getActivityAsUser(
3852 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3853 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3854 null, new UserHandle(userId)).getIntentSender();
3855 } finally {
3856 Binder.restoreCallingIdentity(identity);
3857 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003858 }
3859
3860 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3861 int uid, RemoteCallback callback) {
3862 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3863 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3864 @Override
3865 public void onResult(Bundle value) throws RemoteException {
3866 handleAuthenticatorResponse(true);
3867 }
3868
3869 @Override
3870 public void onRequestContinued() {
3871 /* ignore */
3872 }
3873
3874 @Override
3875 public void onError(int errorCode, String errorMessage) throws RemoteException {
3876 handleAuthenticatorResponse(false);
3877 }
3878
3879 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3880 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003881 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003882 UserHandle.getUserHandleForUid(uid));
3883 if (callback != null) {
3884 Bundle result = new Bundle();
3885 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3886 callback.sendResult(result);
3887 }
3888 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003889 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003890 }
3891
3892 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003893 public boolean someUserHasAccount(@NonNull final Account account) {
3894 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3895 throw new SecurityException("Only system can check for accounts across users");
3896 }
3897 final long token = Binder.clearCallingIdentity();
3898 try {
3899 AccountAndUser[] allAccounts = getAllAccounts();
3900 for (int i = allAccounts.length - 1; i >= 0; i--) {
3901 if (allAccounts[i].account.equals(account)) {
3902 return true;
3903 }
3904 }
3905 return false;
3906 } finally {
3907 Binder.restoreCallingIdentity(token);
3908 }
3909 }
3910
Fred Quintana33269202009-04-20 16:05:10 -07003911 private class GetAccountsByTypeAndFeatureSession extends Session {
3912 private final String[] mFeatures;
3913 private volatile Account[] mAccountsOfType = null;
3914 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3915 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003916 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003917 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003918
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003919 public GetAccountsByTypeAndFeatureSession(
3920 UserAccounts accounts,
3921 IAccountManagerResponse response,
3922 String type,
3923 String[] features,
3924 int callingUid,
3925 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003926 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003927 true /* stripAuthTokenFromResult */, null /* accountName */,
3928 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003929 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003930 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003931 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003932 }
3933
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003934 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003935 public void run() throws RemoteException {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07003936 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
3937 mCallingUid, mPackageName, false /* include managed not visible*/);
Fred Quintana33269202009-04-20 16:05:10 -07003938 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003939 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003940 mCurrentAccount = 0;
3941
3942 checkAccount();
3943 }
3944
3945 public void checkAccount() {
3946 if (mCurrentAccount >= mAccountsOfType.length) {
3947 sendResult();
3948 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003949 }
Fred Quintana33269202009-04-20 16:05:10 -07003950
Fred Quintana29e94b82010-03-10 12:11:51 -08003951 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3952 if (accountAuthenticator == null) {
3953 // It is possible that the authenticator has died, which is indicated by
3954 // mAuthenticator being set to null. If this happens then just abort.
3955 // There is no need to send back a result or error in this case since
3956 // that already happened when mAuthenticator was cleared.
3957 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3958 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3959 + " connected to the authenticator, " + toDebugString());
3960 }
3961 return;
3962 }
Fred Quintana33269202009-04-20 16:05:10 -07003963 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003964 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003965 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003966 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003967 }
3968 }
3969
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003970 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003971 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003972 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003973 mNumResults++;
3974 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003975 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003976 return;
3977 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003978 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003979 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3980 }
3981 mCurrentAccount++;
3982 checkAccount();
3983 }
3984
3985 public void sendResult() {
3986 IAccountManagerResponse response = getResponseAndClose();
3987 if (response != null) {
3988 try {
3989 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3990 for (int i = 0; i < accounts.length; i++) {
3991 accounts[i] = mAccountsWithFeatures.get(i);
3992 }
Fred Quintana56285a62010-12-02 14:20:51 -08003993 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3994 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3995 + response);
3996 }
Fred Quintana33269202009-04-20 16:05:10 -07003997 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003998 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07003999 response.onResult(result);
4000 } catch (RemoteException e) {
4001 // if the caller is dead then there is no one to care about remote exceptions
4002 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4003 Log.v(TAG, "failure while notifying response", e);
4004 }
4005 }
4006 }
4007 }
4008
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004009 @Override
Fred Quintana33269202009-04-20 16:05:10 -07004010 protected String toDebugString(long now) {
4011 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
4012 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
4013 }
4014 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004015
Amith Yamasani04e0d262012-02-14 11:50:53 -08004016 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004017 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08004018 * @hide
4019 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004020 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004021 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004022 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004023 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07004024 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4025 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004026 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004027 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004028 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004029 long identityToken = clearCallingIdentity();
4030 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004031 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004032 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004033 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004034 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004035 opPackageName,
4036 visibleAccountTypes,
4037 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08004038 } finally {
4039 restoreCallingIdentity(identityToken);
4040 }
4041 }
4042
Amith Yamasanif29f2362012-04-05 18:29:52 -07004043 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004044 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004045 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004046 * @hide
4047 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004048 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004049 public AccountAndUser[] getRunningAccounts() {
4050 final int[] runningUserIds;
4051 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004052 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004053 } catch (RemoteException e) {
4054 // Running in system_server; should never happen
4055 throw new RuntimeException(e);
4056 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004057 return getAccounts(runningUserIds);
4058 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004059
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004060 /**
4061 * Returns accounts for all users, ignores visibility values.
4062 *
4063 * @hide
4064 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004065 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004066 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004067 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004068 final int[] userIds = new int[users.size()];
4069 for (int i = 0; i < userIds.length; i++) {
4070 userIds[i] = users.get(i).id;
4071 }
4072 return getAccounts(userIds);
4073 }
4074
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004075 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004076 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004077 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004078 for (int userId : userIds) {
4079 UserAccounts userAccounts = getUserAccounts(userId);
4080 if (userAccounts == null) continue;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004081 Account[] accounts = getAccountsFromCache(
4082 userAccounts,
4083 null /* type */,
4084 Binder.getCallingUid(),
4085 null /* packageName */,
4086 false /* include managed not visible*/);
4087 for (Account account : accounts) {
4088 runningAccounts.add(new AccountAndUser(account, userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004089 }
4090 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004091
4092 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4093 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004094 }
4095
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004096 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004097 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004098 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004099 int callingUid = Binder.getCallingUid();
4100 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004101 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004102 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004103 }
4104
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004105 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004106 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004107 String type,
4108 int userId,
4109 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004110 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004111 String opPackageName,
4112 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004113 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004114 // Only allow the system process to read accounts of other users
4115 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004116 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004117 && mContext.checkCallingOrSelfPermission(
4118 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4119 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004120 throw new SecurityException("User " + UserHandle.getCallingUserId()
4121 + " trying to get account for " + userId);
4122 }
4123
Fred Quintana56285a62010-12-02 14:20:51 -08004124 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4125 Log.v(TAG, "getAccounts: accountType " + type
4126 + ", caller's uid " + Binder.getCallingUid()
4127 + ", pid " + Binder.getCallingPid());
4128 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004129
4130 // If the original calling app was using account choosing activity
4131 // provided by the framework or authenticator we'll passing in
4132 // the original caller's uid here, which is what should be used for filtering.
4133 List<String> managedTypes =
4134 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4135 if (packageUid != -1 &&
4136 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4137 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004138 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004139 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004140 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004141 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4142 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004143 if (visibleAccountTypes.isEmpty()
4144 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004145 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004146 } else if (visibleAccountTypes.contains(type)) {
4147 // Prune the list down to just the requested type.
4148 visibleAccountTypes = new ArrayList<>();
4149 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004150 } // else aggregate all the visible accounts (it won't matter if the
4151 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004152
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004153 long identityToken = clearCallingIdentity();
4154 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004155 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004156 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004157 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004158 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004159 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004160 visibleAccountTypes,
4161 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004162 } finally {
4163 restoreCallingIdentity(identityToken);
4164 }
4165 }
4166
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004167 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004168 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004169 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004170 int callingUid,
4171 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004172 List<String> visibleAccountTypes,
4173 boolean includeUserManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004174 ArrayList<Account> visibleAccounts = new ArrayList<>();
4175 for (String visibleType : visibleAccountTypes) {
4176 Account[] accountsForType = getAccountsFromCache(
4177 userAccounts, visibleType, callingUid, callingPackage,
4178 includeUserManagedNotVisible);
4179 if (accountsForType != null) {
4180 visibleAccounts.addAll(Arrays.asList(accountsForType));
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004181 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004182 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004183 Account[] result = new Account[visibleAccounts.size()];
4184 for (int i = 0; i < visibleAccounts.size(); i++) {
4185 result[i] = visibleAccounts.get(i);
4186 }
4187 return result;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004188 }
4189
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004190 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004191 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4192 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004193 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004194 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004195 for (Account account : accounts) {
4196 addSharedAccountAsUser(account, userId);
4197 }
4198 }
4199
4200 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004201 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004202 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004203 accounts.accountsDb.deleteSharedAccount(account);
4204 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004205 if (accountId < 0) {
4206 Log.w(TAG, "insertAccountIntoDatabase: " + account
4207 + ", skipping the DB insert failed");
4208 return false;
4209 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004210 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4211 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004212 return true;
4213 }
4214
4215 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004216 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4217 userId = handleIncomingUser(userId);
4218 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004219 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4220 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004221 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004222 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004223 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004224 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004225 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004226 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004227 }
4228 return r > 0;
4229 }
4230
4231 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004232 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004233 return removeSharedAccountAsUser(account, userId, getCallingUid());
4234 }
4235
4236 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004237 userId = handleIncomingUser(userId);
4238 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004239 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4240 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004241 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004242 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004243 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004244 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004245 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004246 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004247 }
4248
4249 @Override
4250 public Account[] getSharedAccountsAsUser(int userId) {
4251 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004252 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004253 synchronized (accounts.dbLock) {
4254 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
4255 Account[] accountArray = new Account[accountList.size()];
4256 accountList.toArray(accountArray);
4257 return accountArray;
4258 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004259 }
4260
4261 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004262 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004263 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004264 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004265 }
4266
Amith Yamasani27db4682013-03-30 17:07:47 -07004267 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004268 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004269 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004270 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004271 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004272 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004273 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4274 + callingUid + " with uid=" + uid);
4275 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004276 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004277 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004278 }
4279
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004280 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004281 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004282 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4283 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004284 int callingUid = Binder.getCallingUid();
4285 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004286 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004287 int packageUid = -1;
4288 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004289 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4290 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004291 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004292 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004293 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004294 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004295 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4296 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004297 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004298 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004299 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004300 }
4301
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004302 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004303 public void getAccountsByFeatures(
4304 IAccountManagerResponse response,
4305 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004306 String[] features,
4307 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004308 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004309 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004310 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4311 Log.v(TAG, "getAccounts: accountType " + type
4312 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004313 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004314 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004315 + ", pid " + Binder.getCallingPid());
4316 }
Fred Quintana382601f2010-03-25 12:25:10 -07004317 if (response == null) throw new IllegalArgumentException("response is null");
4318 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004319 int userId = UserHandle.getCallingUserId();
4320
Svetoslavf3f02ac2015-09-08 14:36:35 -07004321 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4322 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004323 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004324 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004325 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004326 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004327 try {
4328 response.onResult(result);
4329 } catch (RemoteException e) {
4330 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4331 }
4332 return;
4333 }
Fred Quintana33269202009-04-20 16:05:10 -07004334 long identityToken = clearCallingIdentity();
4335 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004336 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004337 if (features == null || features.length == 0) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004338 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid,
4339 opPackageName, false);
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004340 Bundle result = new Bundle();
4341 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4342 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004343 return;
4344 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004345 new GetAccountsByTypeAndFeatureSession(
4346 userAccounts,
4347 response,
4348 type,
4349 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004350 callingUid,
4351 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004352 } finally {
4353 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004354 }
4355 }
4356
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004357 @Override
4358 public void onAccountAccessed(String token) throws RemoteException {
4359 final int uid = Binder.getCallingUid();
4360 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4361 return;
4362 }
4363 final int userId = UserHandle.getCallingUserId();
4364 final long identity = Binder.clearCallingIdentity();
4365 try {
4366 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4367 if (Objects.equals(account.getAccessId(), token)) {
4368 // An app just accessed the account. At this point it knows about
4369 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004370 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004371 if (!hasAccountAccess(account, null, uid)) {
4372 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4373 uid, true);
4374 }
4375 }
4376 }
4377 } finally {
4378 Binder.restoreCallingIdentity(identity);
4379 }
4380 }
4381
Fred Quintanaa698f422009-04-08 19:14:54 -07004382 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004383 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004384 IAccountManagerResponse mResponse;
4385 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004386 final boolean mExpectActivityLaunch;
4387 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004388 final String mAccountName;
4389 // Indicates if we need to add auth details(like last credential time)
4390 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004391 // If set, we need to update the last authenticated time. This is
4392 // currently
4393 // used on
4394 // successful confirming credentials.
4395 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004396
Fred Quintana33269202009-04-20 16:05:10 -07004397 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004398 private int mNumRequestContinued = 0;
4399 private int mNumErrors = 0;
4400
Fred Quintana60307342009-03-24 22:48:12 -07004401 IAccountAuthenticator mAuthenticator = null;
4402
Fred Quintana8570f742010-02-18 10:32:54 -08004403 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004404 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004405
Amith Yamasani04e0d262012-02-14 11:50:53 -08004406 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004407 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4408 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004409 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4410 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4411 }
4412
4413 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4414 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4415 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004416 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004417 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004418 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004419 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004420 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004421 mResponse = response;
4422 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004423 mExpectActivityLaunch = expectActivityLaunch;
4424 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004425 mAccountName = accountName;
4426 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004427 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004428
Fred Quintanaa698f422009-04-08 19:14:54 -07004429 synchronized (mSessions) {
4430 mSessions.put(toString(), this);
4431 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004432 if (response != null) {
4433 try {
4434 response.asBinder().linkToDeath(this, 0 /* flags */);
4435 } catch (RemoteException e) {
4436 mResponse = null;
4437 binderDied();
4438 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004439 }
Fred Quintana60307342009-03-24 22:48:12 -07004440 }
4441
Fred Quintanaa698f422009-04-08 19:14:54 -07004442 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004443 if (mResponse == null) {
4444 // this session has already been closed
4445 return null;
4446 }
Fred Quintana60307342009-03-24 22:48:12 -07004447 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004448 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004449 return response;
4450 }
4451
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004452 /**
4453 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4454 * security policy.
4455 *
4456 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004457 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004458 * supplied entries in the system Settings app.
4459 */
4460 protected void checkKeyIntent(
4461 int authUid,
4462 Intent intent) throws SecurityException {
4463 long bid = Binder.clearCallingIdentity();
4464 try {
4465 PackageManager pm = mContext.getPackageManager();
4466 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4467 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4468 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004469 if (!isExportedSystemActivity(targetActivityInfo)
4470 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4471 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004472 String pkgName = targetActivityInfo.packageName;
4473 String activityName = targetActivityInfo.name;
4474 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4475 + "does not share a signature with the supplying authenticator (%s).";
4476 throw new SecurityException(
4477 String.format(tmpl, activityName, pkgName, mAccountType));
4478 }
4479 } finally {
4480 Binder.restoreCallingIdentity(bid);
4481 }
4482 }
4483
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004484 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4485 String className = activityInfo.name;
4486 return "android".equals(activityInfo.packageName) &&
4487 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4488 || CantAddAccountActivity.class.getName().equals(className));
4489 }
4490
Fred Quintanaa698f422009-04-08 19:14:54 -07004491 private void close() {
4492 synchronized (mSessions) {
4493 if (mSessions.remove(toString()) == null) {
4494 // the session was already closed, so bail out now
4495 return;
4496 }
4497 }
4498 if (mResponse != null) {
4499 // stop listening for response deaths
4500 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4501
4502 // clear this so that we don't accidentally send any further results
4503 mResponse = null;
4504 }
4505 cancelTimeout();
4506 unbind();
4507 }
4508
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004509 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004510 public void binderDied() {
4511 mResponse = null;
4512 close();
4513 }
4514
4515 protected String toDebugString() {
4516 return toDebugString(SystemClock.elapsedRealtime());
4517 }
4518
4519 protected String toDebugString(long now) {
4520 return "Session: expectLaunch " + mExpectActivityLaunch
4521 + ", connected " + (mAuthenticator != null)
4522 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4523 + "/" + mNumErrors + ")"
4524 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4525 }
4526
Fred Quintana60307342009-03-24 22:48:12 -07004527 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004528 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4529 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4530 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004531 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004532 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004533 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004534 }
4535 }
4536
4537 private void unbind() {
4538 if (mAuthenticator != null) {
4539 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004540 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004541 }
4542 }
4543
Fred Quintana60307342009-03-24 22:48:12 -07004544 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004545 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004546 }
4547
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004548 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004549 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004550 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004551 try {
4552 run();
4553 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004554 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004555 "remote exception");
4556 }
Fred Quintana60307342009-03-24 22:48:12 -07004557 }
4558
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004559 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004560 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004561 mAuthenticator = null;
4562 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004563 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004564 try {
4565 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4566 "disconnected");
4567 } catch (RemoteException e) {
4568 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4569 Log.v(TAG, "Session.onServiceDisconnected: "
4570 + "caught RemoteException while responding", e);
4571 }
4572 }
Fred Quintana60307342009-03-24 22:48:12 -07004573 }
4574 }
4575
Fred Quintanab839afc2009-10-14 15:57:28 -07004576 public abstract void run() throws RemoteException;
4577
Fred Quintana60307342009-03-24 22:48:12 -07004578 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004579 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004580 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004581 try {
4582 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4583 "timeout");
4584 } catch (RemoteException e) {
4585 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4586 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4587 e);
4588 }
4589 }
Fred Quintana60307342009-03-24 22:48:12 -07004590 }
4591 }
4592
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004593 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004594 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004595 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004596 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004597 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004598 if (result != null) {
4599 boolean isSuccessfulConfirmCreds = result.getBoolean(
4600 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004601 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004602 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4603 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004604 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004605 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4606 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004607 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004608 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004609 if (needUpdate || mAuthDetailsRequired) {
4610 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4611 if (needUpdate && accountPresent) {
4612 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4613 }
4614 if (mAuthDetailsRequired) {
4615 long lastAuthenticatedTime = -1;
4616 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004617 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004618 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004619 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004620 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004621 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004622 lastAuthenticatedTime);
4623 }
4624 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004625 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004626 if (result != null
4627 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004628 checkKeyIntent(
4629 Binder.getCallingUid(),
4630 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004631 }
4632 if (result != null
4633 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004634 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4635 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004636 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4637 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004638 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4639 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004640 }
Fred Quintana60307342009-03-24 22:48:12 -07004641 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004642 IAccountManagerResponse response;
4643 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004644 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004645 response = mResponse;
4646 } else {
4647 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004648 }
Fred Quintana60307342009-03-24 22:48:12 -07004649 if (response != null) {
4650 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004651 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004652 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4653 Log.v(TAG, getClass().getSimpleName()
4654 + " calling onError() on response " + response);
4655 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004656 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004657 "null bundle returned");
4658 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004659 if (mStripAuthTokenFromResult) {
4660 result.remove(AccountManager.KEY_AUTHTOKEN);
4661 }
Fred Quintana56285a62010-12-02 14:20:51 -08004662 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4663 Log.v(TAG, getClass().getSimpleName()
4664 + " calling onResult() on response " + response);
4665 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004666 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4667 (intent == null)) {
4668 // All AccountManager error codes are greater than 0
4669 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4670 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4671 } else {
4672 response.onResult(result);
4673 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004674 }
Fred Quintana60307342009-03-24 22:48:12 -07004675 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004676 // if the caller is dead then there is no one to care about remote exceptions
4677 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4678 Log.v(TAG, "failure while notifying response", e);
4679 }
Fred Quintana60307342009-03-24 22:48:12 -07004680 }
4681 }
4682 }
Fred Quintana60307342009-03-24 22:48:12 -07004683
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004684 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004685 public void onRequestContinued() {
4686 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004687 }
4688
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004689 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004690 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004691 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004692 IAccountManagerResponse response = getResponseAndClose();
4693 if (response != null) {
4694 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004695 Log.v(TAG, getClass().getSimpleName()
4696 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004697 }
4698 try {
4699 response.onError(errorCode, errorMessage);
4700 } catch (RemoteException e) {
4701 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4702 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4703 }
4704 }
4705 } else {
4706 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4707 Log.v(TAG, "Session.onError: already closed");
4708 }
Fred Quintana60307342009-03-24 22:48:12 -07004709 }
4710 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004711
4712 /**
4713 * find the component name for the authenticator and initiate a bind
4714 * if no authenticator or the bind fails then return false, otherwise return true
4715 */
4716 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004717 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4718 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4719 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004720 if (authenticatorInfo == null) {
4721 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4722 Log.v(TAG, "there is no authenticator for " + authenticatorType
4723 + ", bailing out");
4724 }
4725 return false;
4726 }
4727
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004728 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004729 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004730 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4731 + " which isn't encryption aware");
4732 return false;
4733 }
4734
Fred Quintanab839afc2009-10-14 15:57:28 -07004735 Intent intent = new Intent();
4736 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4737 intent.setComponent(authenticatorInfo.componentName);
4738 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4739 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4740 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004741 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004742 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004743 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4744 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4745 }
4746 return false;
4747 }
4748
Fred Quintanab839afc2009-10-14 15:57:28 -07004749 return true;
4750 }
Fred Quintana60307342009-03-24 22:48:12 -07004751 }
4752
Svet Ganov5d09c992016-09-07 09:57:41 -07004753 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004754 MessageHandler(Looper looper) {
4755 super(looper);
4756 }
Costin Manolache3348f142009-09-29 18:58:36 -07004757
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004758 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004759 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004760 switch (msg.what) {
4761 case MESSAGE_TIMED_OUT:
4762 Session session = (Session)msg.obj;
4763 session.onTimedOut();
4764 break;
4765
Amith Yamasani5be347b2013-03-31 17:44:31 -07004766 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004767 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004768 break;
4769
Fred Quintana60307342009-03-24 22:48:12 -07004770 default:
4771 throw new IllegalStateException("unhandled message: " + msg.what);
4772 }
4773 }
4774 }
4775
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004776 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004777 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004778 }
4779
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004780 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004781 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004782 }
4783
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004784 /*
4785 * This function receives an opened writable database.
4786 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004787 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004788 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004789 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004790 }
4791
4792 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004793 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004794 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004795 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004796 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004797
4798 class LogRecordTask implements Runnable {
4799 private final String action;
4800 private final String tableName;
4801 private final long accountId;
4802 private final UserAccounts userAccount;
4803 private final int callingUid;
4804 private final long userDebugDbInsertionPoint;
4805
4806 LogRecordTask(final String action,
4807 final String tableName,
4808 final long accountId,
4809 final UserAccounts userAccount,
4810 final int callingUid,
4811 final long userDebugDbInsertionPoint) {
4812 this.action = action;
4813 this.tableName = tableName;
4814 this.accountId = accountId;
4815 this.userAccount = userAccount;
4816 this.callingUid = callingUid;
4817 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4818 }
4819
4820 public void run() {
4821 SQLiteStatement logStatement = userAccount.statementForLogging;
4822 logStatement.bindLong(1, accountId);
4823 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004824 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004825 logStatement.bindLong(4, callingUid);
4826 logStatement.bindString(5, tableName);
4827 logStatement.bindLong(6, userDebugDbInsertionPoint);
4828 logStatement.execute();
4829 logStatement.clearBindings();
4830 }
4831 }
4832
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004833 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4834 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004835 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004836 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004837 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004838 }
4839
4840 /*
4841 * This should only be called once to compile the sql statement for logging
4842 * and to find the insertion point.
4843 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004844 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4845 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4846 .calculateDebugTableInsertionPoint();
4847 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004848 }
4849
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004850 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004851 return asBinder();
4852 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004853
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004854 /**
4855 * Searches array of arguments for the specified string
4856 * @param args array of argument strings
4857 * @param value value to search for
4858 * @return true if the value is contained in the array
4859 */
4860 private static boolean scanArgs(String[] args, String value) {
4861 if (args != null) {
4862 for (String arg : args) {
4863 if (value.equals(arg)) {
4864 return true;
4865 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004866 }
4867 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004868 return false;
4869 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004870
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004871 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004872 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004873 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004874 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004875 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004876
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004877 final List<UserInfo> users = getUserManager().getUsers();
4878 for (UserInfo user : users) {
4879 ipw.println("User " + user + ":");
4880 ipw.increaseIndent();
4881 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4882 ipw.println();
4883 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004884 }
4885 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004886
Amith Yamasani04e0d262012-02-14 11:50:53 -08004887 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4888 String[] args, boolean isCheckinRequest) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004889 if (isCheckinRequest) {
4890 // This is a checkin request. *Only* upload the account types and the count of
4891 // each.
4892 synchronized (userAccounts.dbLock) {
4893 userAccounts.accountsDb.dumpDeAccountsTable(fout);
4894 }
4895 } else {
4896 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */,
4897 Process.SYSTEM_UID, null /* packageName */, false);
4898 fout.println("Accounts: " + accounts.length);
4899 for (Account account : accounts) {
4900 fout.println(" " + account);
4901 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004902
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004903 // Add debug information.
4904 fout.println();
4905 synchronized (userAccounts.dbLock) {
4906 userAccounts.accountsDb.dumpDebugTable(fout);
4907 }
4908 fout.println();
4909 synchronized (mSessions) {
4910 final long now = SystemClock.elapsedRealtime();
4911 fout.println("Active Sessions: " + mSessions.size());
4912 for (Session session : mSessions.values()) {
4913 fout.println(" " + session.toDebugString(now));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07004914 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004915 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07004916
4917 fout.println();
4918 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004919 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004920 }
4921
Amith Yamasani04e0d262012-02-14 11:50:53 -08004922 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004923 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004924 long identityToken = clearCallingIdentity();
4925 try {
4926 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4927 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4928 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004929
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004930 if (intent.getComponent() != null &&
4931 GrantCredentialsPermissionActivity.class.getName().equals(
4932 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004933 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004934 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004935 Context contextForUser = getContextForUser(new UserHandle(userId));
Chris Wren717a8812017-03-31 15:34:39 -04004936 final NotificationId id = getSigninRequiredNotificationId(accounts, account);
4937 intent.addCategory(id.mTag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004938
Fred Quintana33f889a2009-09-14 17:31:26 -07004939 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004940 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004941 Notification n =
4942 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004943 .setWhen(0)
4944 .setSmallIcon(android.R.drawable.stat_sys_warning)
4945 .setColor(contextForUser.getColor(
4946 com.android.internal.R.color.system_notification_accent_color))
4947 .setContentTitle(String.format(notificationTitleFormat, account.name))
4948 .setContentText(message)
4949 .setContentIntent(PendingIntent.getActivityAsUser(
4950 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004951 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004952 .build();
Chris Wren717a8812017-03-31 15:34:39 -04004953 installNotification(id, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004954 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004955 } finally {
4956 restoreCallingIdentity(identityToken);
4957 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004958 }
4959
Chris Wren717a8812017-03-31 15:34:39 -04004960 private void installNotification(NotificationId id, final Notification notification,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004961 String packageName, int userId) {
4962 final long token = clearCallingIdentity();
4963 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004964 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004965 try {
Chris Wren717a8812017-03-31 15:34:39 -04004966 notificationManager.enqueueNotificationWithTag(packageName, packageName,
4967 id.mTag, id.mId, notification, new int[1], userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004968 } catch (RemoteException e) {
4969 /* ignore - local call */
4970 }
4971 } finally {
4972 Binder.restoreCallingIdentity(token);
4973 }
Fred Quintana56285a62010-12-02 14:20:51 -08004974 }
4975
Chris Wren717a8812017-03-31 15:34:39 -04004976 private void cancelNotification(NotificationId id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004977 cancelNotification(id, mContext.getPackageName(), user);
4978 }
4979
Chris Wren717a8812017-03-31 15:34:39 -04004980 private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004981 long identityToken = clearCallingIdentity();
4982 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004983 INotificationManager service = mInjector.getNotificationManager();
Chris Wren717a8812017-03-31 15:34:39 -04004984 service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004985 } catch (RemoteException e) {
4986 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004987 } finally {
4988 restoreCallingIdentity(identityToken);
4989 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004990 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004991
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004992 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
4993 final long identity = Binder.clearCallingIdentity();
4994 try {
4995 IPackageManager pm = ActivityThread.getPackageManager();
4996 for (String perm : permissions) {
4997 if (pm.checkPermission(perm, packageName, userId)
4998 == PackageManager.PERMISSION_GRANTED) {
4999 return true;
5000 }
5001 }
5002 } catch (RemoteException e) {
5003 /* ignore - local call */
5004 } finally {
5005 Binder.restoreCallingIdentity(identity);
5006 }
5007 return false;
5008 }
5009
Ian Pedowitz358e51f2016-03-15 17:08:27 +00005010 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
5011 for (String perm : permissions) {
5012 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
5013 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5014 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
5015 }
5016 final int opCode = AppOpsManager.permissionToOpCode(perm);
5017 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
5018 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
5019 return true;
5020 }
5021 }
5022 }
5023 return false;
5024 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005025
Amith Yamasani67df64b2012-12-14 12:09:36 -08005026 private int handleIncomingUser(int userId) {
5027 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005028 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08005029 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
5030 } catch (RemoteException re) {
5031 // Shouldn't happen, local.
5032 }
5033 return userId;
5034 }
5035
Christopher Tateccbf84f2013-05-08 15:25:41 -07005036 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005037 String[] packages;
5038 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005039 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005040 packages = mPackageManager.getPackagesForUid(callingUid);
5041 } finally {
5042 Binder.restoreCallingIdentity(identityToken);
5043 }
5044 if (packages == null) {
5045 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005046 return false;
5047 }
Fred Quintana7be59642009-08-24 18:29:25 -07005048 for (String name : packages) {
5049 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005050 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08005051 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08005052 && (packageInfo.applicationInfo.privateFlags
5053 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07005054 return true;
5055 }
5056 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005057 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07005058 return false;
5059 }
5060 }
5061 return false;
5062 }
5063
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005064 private boolean permissionIsGranted(
5065 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005066 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5067 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5068 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5069 }
5070 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005071 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005072
5073 if (isPrivileged(callerUid)) {
5074 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5075 Log.v(TAG, "Access to " + account + " granted calling uid "
5076 + callerUid + " privileged");
5077 }
5078 return true;
5079 }
5080 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5081 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5082 Log.v(TAG, "Access to " + account + " granted calling uid "
5083 + callerUid + " manages the account");
5084 }
5085 return true;
5086 }
5087 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5088 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5089 Log.v(TAG, "Access to " + account + " granted calling uid "
5090 + callerUid + " user granted access");
5091 }
5092 return true;
5093 }
5094
5095 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5096 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5097 }
5098
5099 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005100 }
5101
Svetoslavf3f02ac2015-09-08 14:36:35 -07005102 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5103 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005104 if (accountType == null) {
5105 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005106 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005107 return getTypesVisibleToCaller(callingUid, userId,
5108 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005109 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005110 }
5111
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005112 // Method checks visibility for applications targeing API level below {@link
5113 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005114 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005115 private boolean checkGetAccountsPermission(String packageName, int userId) {
5116 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5117 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5118 }
5119
5120 private boolean checkReadContactsPermission(String packageName, int userId) {
5121 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5122 }
5123
5124 /**
5125 * Method checks package uid and signature with Authenticator which manages accountType.
5126 *
5127 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5128 * SIGNATURE_CHECK_MISMATCH otherwise.
5129 */
5130 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5131 if (accountType == null) {
5132 return SIGNATURE_CHECK_MISMATCH;
5133 }
5134
5135 long identityToken = Binder.clearCallingIdentity();
5136 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5137 try {
5138 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5139 } finally {
5140 Binder.restoreCallingIdentity(identityToken);
5141 }
5142 // Check for signature match with Authenticator.
5143 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5144 : serviceInfos) {
5145 if (accountType.equals(serviceInfo.type.type)) {
5146 if (serviceInfo.uid == callingUid) {
5147 return SIGNATURE_CHECK_UID_MATCH;
5148 }
5149 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5150 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5151 return SIGNATURE_CHECK_MATCH;
5152 }
5153 }
5154 }
5155 return SIGNATURE_CHECK_MISMATCH;
5156 }
5157
5158 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005159 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5160 if (accountType == null) {
5161 return false;
5162 } else {
5163 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5164 }
5165 }
5166
Svetoslavf3f02ac2015-09-08 14:36:35 -07005167 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5168 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005169 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005170 }
5171
5172 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005173 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005174 }
5175
5176 private List<String> getTypesForCaller(
5177 int callingUid, int userId, boolean isOtherwisePermitted) {
5178 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005179 long identityToken = Binder.clearCallingIdentity();
5180 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5181 try {
5182 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5183 } finally {
5184 Binder.restoreCallingIdentity(identityToken);
5185 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005186 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005187 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005188 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5189 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005190 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005191 }
5192 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005193 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005194 }
5195
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005196 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5197 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5198 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5199 if (account.name.equals(accountName)) {
5200 return true;
5201 }
5202 }
5203 }
5204 return false;
5205 }
5206
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005207 private static void checkManageUsersPermission(String message) {
5208 if (ActivityManager.checkComponentPermission(
5209 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5210 != PackageManager.PERMISSION_GRANTED) {
5211 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5212 }
5213 }
5214
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005215 private static void checkManageOrCreateUsersPermission(String message) {
5216 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5217 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5218 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5219 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5220 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5221 + message);
5222 }
5223 }
5224
Amith Yamasani04e0d262012-02-14 11:50:53 -08005225 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5226 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005227 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005228 return true;
5229 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005230 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005231 synchronized (accounts.dbLock) {
5232 synchronized (accounts.cacheLock) {
5233 long grantsCount;
5234 if (authTokenType != null) {
5235 grantsCount = accounts.accountsDb
5236 .findMatchingGrantsCount(callerUid, authTokenType, account);
5237 } else {
5238 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
5239 account);
5240 }
5241 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005242
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005243 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5244 // TODO: Skip this check when running automated tests. Replace this
5245 // with a more general solution.
5246 Log.d(TAG, "no credentials permission for usage of " + account + ", "
5247 + authTokenType + " by uid " + callerUid
5248 + " but ignoring since device is in test harness.");
5249 return true;
5250 }
5251 return permissionGranted;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005252 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005253 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005254 }
5255
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005256 private boolean isSystemUid(int callingUid) {
5257 String[] packages = null;
5258 long ident = Binder.clearCallingIdentity();
5259 try {
5260 packages = mPackageManager.getPackagesForUid(callingUid);
5261 } finally {
5262 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005263 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005264 if (packages != null) {
5265 for (String name : packages) {
5266 try {
5267 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5268 if (packageInfo != null
5269 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5270 != 0) {
5271 return true;
5272 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005273 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005274 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5275 }
5276 }
5277 } else {
5278 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005279 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005280 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005281 }
5282
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005283 /** Succeeds if any of the specified permissions are granted. */
5284 private void checkReadAccountsPermitted(
5285 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005286 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005287 int userId,
5288 String opPackageName) {
5289 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005290 String msg = String.format(
5291 "caller uid %s cannot access %s accounts",
5292 callingUid,
5293 accountType);
5294 Log.w(TAG, " " + msg);
5295 throw new SecurityException(msg);
5296 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005297 }
5298
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005299 private boolean canUserModifyAccounts(int userId, int callingUid) {
5300 // the managing app can always modify accounts
5301 if (isProfileOwner(callingUid)) {
5302 return true;
5303 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005304 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5305 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5306 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005307 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005308 return true;
5309 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005310
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005311 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5312 // the managing app can always modify accounts
5313 if (isProfileOwner(callingUid)) {
5314 return true;
5315 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005316 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5317 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005318 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005319 if (typesArray == null) {
5320 return true;
5321 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005322 for (String forbiddenType : typesArray) {
5323 if (forbiddenType.equals(accountType)) {
5324 return false;
5325 }
5326 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005327 return true;
5328 }
5329
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005330 private boolean isProfileOwner(int uid) {
5331 final DevicePolicyManagerInternal dpmi =
5332 LocalServices.getService(DevicePolicyManagerInternal.class);
5333 return (dpmi != null)
5334 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5335 }
5336
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005337 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005338 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5339 throws RemoteException {
5340 final int callingUid = getCallingUid();
5341
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005342 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005343 throw new SecurityException();
5344 }
5345
5346 if (value) {
5347 grantAppPermission(account, authTokenType, uid);
5348 } else {
5349 revokeAppPermission(account, authTokenType, uid);
5350 }
5351 }
5352
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005353 /**
5354 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5355 * <p>
5356 * Although this is public it can only be accessed via the AccountManagerService object
5357 * which is in the system. This means we don't need to protect it with permissions.
5358 * @hide
5359 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005360 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005361 if (account == null || authTokenType == null) {
5362 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005363 return;
5364 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005365 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005366 synchronized (accounts.dbLock) {
5367 synchronized (accounts.cacheLock) {
5368 long accountId = accounts.accountsDb.findDeAccountId(account);
5369 if (accountId >= 0) {
5370 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
5371 }
5372 cancelNotification(
5373 getCredentialPermissionNotificationId(account, authTokenType, uid),
5374 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005375
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005376 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
5377 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005378 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005379
5380 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5381 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5382 : mAppPermissionChangeListeners) {
5383 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5384 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005385 }
5386
5387 /**
5388 * Don't allow callers with the given uid permission to get credentials for
5389 * account/authTokenType.
5390 * <p>
5391 * Although this is public it can only be accessed via the AccountManagerService object
5392 * which is in the system. This means we don't need to protect it with permissions.
5393 * @hide
5394 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005395 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005396 if (account == null || authTokenType == null) {
5397 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005398 return;
5399 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005400 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005401 synchronized (accounts.dbLock) {
5402 synchronized (accounts.cacheLock) {
5403 accounts.accountsDb.beginTransaction();
5404 try {
5405 long accountId = accounts.accountsDb.findDeAccountId(account);
5406 if (accountId >= 0) {
5407 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5408 accountId, authTokenType, uid);
5409 accounts.accountsDb.setTransactionSuccessful();
5410 }
5411 } finally {
5412 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005413 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005414
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005415 cancelNotification(
5416 getCredentialPermissionNotificationId(account, authTokenType, uid),
5417 UserHandle.of(accounts.userId));
5418 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005419 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005420
5421 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5422 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5423 : mAppPermissionChangeListeners) {
5424 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5425 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005426 }
Fred Quintana56285a62010-12-02 14:20:51 -08005427
Amith Yamasani04e0d262012-02-14 11:50:53 -08005428 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5429 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005430 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005431 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005432 for (Account curAccount : oldAccountsForType) {
5433 if (!curAccount.equals(account)) {
5434 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005435 }
5436 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005437 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005438 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005439 } else {
5440 Account[] newAccountsForType = new Account[newAccountsList.size()];
5441 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005442 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005443 }
Fred Quintana56285a62010-12-02 14:20:51 -08005444 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005445 accounts.userDataCache.remove(account);
5446 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005447 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005448 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005449 }
5450
5451 /**
5452 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005453 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5454 * processes and if you will return this account to apps you should return the result.
5455 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005456 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005457 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005458 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005459 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5460 Account[] newAccountsForType = new Account[oldLength + 1];
5461 if (accountsForType != null) {
5462 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005463 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005464 String token = account.getAccessId() != null ? account.getAccessId()
5465 : UUID.randomUUID().toString();
5466 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005467 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005468 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005469 }
5470
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005471 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005472 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005473 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005474 String visibilityFilterPackage = callingPackage;
5475 if (visibilityFilterPackage == null) {
5476 visibilityFilterPackage = getPackageNameForUid(callingUid);
5477 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005478 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005479 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005480 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005481 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5482 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5483 || (includeManagedNotVisible
5484 && (visibility
5485 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5486 firstPass.put(account, visibility);
5487 }
5488 }
5489 Map<Account, Integer> secondPass =
5490 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5491
5492 Account[] filtered = new Account[secondPass.size()];
5493 filtered = secondPass.keySet().toArray(filtered);
5494 return filtered;
5495 }
5496
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005497 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005498 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005499 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005500 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005501 // first part is to filter shared accounts.
5502 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005503 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005504 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005505 return unfiltered;
5506 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005507 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005508 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005509 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005510 if (packages == null) {
5511 packages = new String[] {};
5512 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005513 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005514 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005515 // This might be a temporary way to specify a visible list
5516 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005517 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5518 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005519 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005520 return unfiltered;
5521 }
5522 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005523 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005524 if (ArrayUtils.isEmpty(sharedAccounts)) {
5525 return unfiltered;
5526 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005527 String requiredAccountType = "";
5528 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005529 // If there's an explicit callingPackage specified, check if that package
5530 // opted in to see restricted accounts.
5531 if (callingPackage != null) {
5532 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005533 if (pi != null && pi.restrictedAccountType != null) {
5534 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005535 }
5536 } else {
5537 // Otherwise check if the callingUid has a package that has opted in
5538 for (String packageName : packages) {
5539 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5540 if (pi != null && pi.restrictedAccountType != null) {
5541 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005542 break;
5543 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005544 }
5545 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005546 } catch (NameNotFoundException e) {
5547 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005548 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005549 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005550 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5551 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005552 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005553 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005554 } else {
5555 boolean found = false;
5556 for (Account shared : sharedAccounts) {
5557 if (shared.equals(account)) {
5558 found = true;
5559 break;
5560 }
5561 }
5562 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005563 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005564 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005565 }
5566 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005567 return filtered;
5568 } else {
5569 return unfiltered;
5570 }
5571 }
5572
Amith Yamasani27db4682013-03-30 17:07:47 -07005573 /*
5574 * packageName can be null. If not null, it should be used to filter out restricted accounts
5575 * that the package is not allowed to access.
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005576 *
5577 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a
5578 * deadlock
Amith Yamasani27db4682013-03-30 17:07:47 -07005579 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005580 @NonNull
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005581 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005582 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005583 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
5584 "Method should not be called with cacheLock");
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005585 if (accountType != null) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005586 Account[] accounts;
5587 synchronized (userAccounts.cacheLock) {
5588 accounts = userAccounts.accountCache.get(accountType);
5589 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005590 if (accounts == null) {
5591 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005592 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005593 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5594 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005595 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005596 } else {
5597 int totalLength = 0;
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005598 Account[] accountsArray;
5599 synchronized (userAccounts.cacheLock) {
5600 for (Account[] accounts : userAccounts.accountCache.values()) {
5601 totalLength += accounts.length;
5602 }
5603 if (totalLength == 0) {
5604 return EMPTY_ACCOUNT_ARRAY;
5605 }
5606 accountsArray = new Account[totalLength];
5607 totalLength = 0;
5608 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
5609 System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
5610 accountsOfType.length);
5611 totalLength += accountsOfType.length;
5612 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005613 }
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005614 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005615 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005616 }
5617 }
5618
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005619 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005620 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005621 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005622 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005623 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005624 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005625 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005626 }
5627 if (value == null) {
5628 userDataForAccount.remove(key);
5629 } else {
5630 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005631 }
5632 }
5633
Carlos Valdivia91979be2015-05-22 14:11:35 -07005634 protected String readCachedTokenInternal(
5635 UserAccounts accounts,
5636 Account account,
5637 String tokenType,
5638 String callingPackage,
5639 byte[] pkgSigDigest) {
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005640 synchronized (accounts.dbLock) {
5641 synchronized (accounts.cacheLock) {
5642 return accounts.accountTokenCaches.get(
5643 account, tokenType, callingPackage, pkgSigDigest);
5644 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07005645 }
5646 }
5647
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005648 /** protected by the {@code dbLock}, {@code cacheLock} */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005649 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005650 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005651 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005652 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005653 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005654 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005655 }
5656 if (value == null) {
5657 authTokensForAccount.remove(key);
5658 } else {
5659 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005660 }
5661 }
5662
Amith Yamasani04e0d262012-02-14 11:50:53 -08005663 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5664 String authTokenType) {
Fyodor Kupolov9ac40f12017-03-28 19:11:17 -07005665 // Fast path - check if account is already cached
5666 synchronized (accounts.cacheLock) {
5667 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5668 if (authTokensForAccount != null) {
5669 return authTokensForAccount.get(authTokenType);
5670 }
5671 }
5672 // If not cached yet - do slow path and sync with db if necessary
Fyodor Kupolov8cd927d2017-03-27 17:02:11 -07005673 synchronized (accounts.dbLock) {
5674 synchronized (accounts.cacheLock) {
5675 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
5676 if (authTokensForAccount == null) {
5677 // need to populate the cache for this account
5678 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
5679 accounts.authTokenCache.put(account, authTokensForAccount);
5680 }
5681 return authTokensForAccount.get(authTokenType);
Fred Quintana56285a62010-12-02 14:20:51 -08005682 }
Fred Quintana56285a62010-12-02 14:20:51 -08005683 }
5684 }
5685
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005686 private String readUserDataInternal(UserAccounts accounts, Account account, String key) {
5687 Map<String, String> userDataForAccount;
5688 // Fast path - check if data is already cached
5689 synchronized (accounts.cacheLock) {
5690 userDataForAccount = accounts.userDataCache.get(account);
5691 }
5692 // If not cached yet - do slow path and sync with db if necessary
Simranjit Kohli858511c2016-03-10 18:36:11 +00005693 if (userDataForAccount == null) {
Fyodor Kupolov3d734992017-03-29 17:28:52 -07005694 synchronized (accounts.dbLock) {
5695 synchronized (accounts.cacheLock) {
5696 userDataForAccount = accounts.userDataCache.get(account);
5697 if (userDataForAccount == null) {
5698 // need to populate the cache for this account
5699 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
5700 accounts.userDataCache.put(account, userDataForAccount);
5701 }
5702 }
5703 }
Fred Quintana56285a62010-12-02 14:20:51 -08005704 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005705 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005706 }
5707
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005708 private Context getContextForUser(UserHandle user) {
5709 try {
5710 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5711 } catch (NameNotFoundException e) {
5712 // Default to mContext, not finding the package system is running as is unlikely.
5713 return mContext;
5714 }
5715 }
Sandra Kwan78812282015-11-04 11:19:47 -08005716
5717 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5718 try {
5719 response.onResult(result);
5720 } catch (RemoteException e) {
5721 // if the caller is dead then there is no one to care about remote
5722 // exceptions
5723 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5724 Log.v(TAG, "failure while notifying response", e);
5725 }
5726 }
5727 }
5728
5729 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5730 String errorMessage) {
5731 try {
5732 response.onError(errorCode, errorMessage);
5733 } catch (RemoteException e) {
5734 // if the caller is dead then there is no one to care about remote
5735 // exceptions
5736 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5737 Log.v(TAG, "failure while notifying response", e);
5738 }
5739 }
5740 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005741
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005742 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005743 private final Object mLock = new Object();
5744
5745 @GuardedBy("mLock")
5746 private AccountManagerBackupHelper mBackupHelper;
5747
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005748 @Override
5749 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5750 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5751 if (account == null) {
5752 Slog.w(TAG, "account cannot be null");
5753 return;
5754 }
5755 if (packageName == null) {
5756 Slog.w(TAG, "packageName cannot be null");
5757 return;
5758 }
5759 if (userId < UserHandle.USER_SYSTEM) {
5760 Slog.w(TAG, "user id must be concrete");
5761 return;
5762 }
5763 if (callback == null) {
5764 Slog.w(TAG, "callback cannot be null");
5765 return;
5766 }
5767
Svet Ganovf6d424f12016-09-20 20:18:53 -07005768 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5769 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005770 Bundle result = new Bundle();
5771 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5772 callback.sendResult(result);
5773 return;
5774 }
5775
5776 final int uid;
5777 try {
5778 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5779 } catch (NameNotFoundException e) {
5780 Slog.e(TAG, "Unknown package " + packageName);
5781 return;
5782 }
5783
5784 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005785 final UserAccounts userAccounts;
5786 synchronized (mUsers) {
5787 userAccounts = mUsers.get(userId);
5788 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04005789 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005790 doNotification(userAccounts, account, null, intent, packageName, userId);
5791 }
5792
5793 @Override
5794 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5795 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5796 mAppPermissionChangeListeners.add(listener);
5797 }
5798
5799 @Override
5800 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5801 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005802 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005803
5804 @Override
5805 public byte[] backupAccountAccessPermissions(int userId) {
5806 synchronized (mLock) {
5807 if (mBackupHelper == null) {
5808 mBackupHelper = new AccountManagerBackupHelper(
5809 AccountManagerService.this, this);
5810 }
5811 return mBackupHelper.backupAccountAccessPermissions(userId);
5812 }
5813 }
5814
5815 @Override
5816 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5817 synchronized (mLock) {
5818 if (mBackupHelper == null) {
5819 mBackupHelper = new AccountManagerBackupHelper(
5820 AccountManagerService.this, this);
5821 }
5822 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5823 }
5824 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005825 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005826
5827 @VisibleForTesting
5828 static class Injector {
5829 private final Context mContext;
5830
5831 public Injector(Context context) {
5832 mContext = context;
5833 }
5834
5835 Looper getMessageHandlerLooper() {
5836 ServiceThread serviceThread = new ServiceThread(TAG,
5837 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5838 serviceThread.start();
5839 return serviceThread.getLooper();
5840 }
5841
5842 Context getContext() {
5843 return mContext;
5844 }
5845
5846 void addLocalService(AccountManagerInternal service) {
5847 LocalServices.addService(AccountManagerInternal.class, service);
5848 }
5849
5850 String getDeDatabaseName(int userId) {
5851 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5852 AccountsDb.DE_DATABASE_NAME);
5853 return databaseFile.getPath();
5854 }
5855
5856 String getCeDatabaseName(int userId) {
5857 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5858 AccountsDb.CE_DATABASE_NAME);
5859 return databaseFile.getPath();
5860 }
5861
5862 String getPreNDatabaseName(int userId) {
5863 File systemDir = Environment.getDataSystemDirectory();
5864 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5865 PRE_N_DATABASE_NAME);
5866 if (userId == 0) {
5867 // Migrate old file, if it exists, to the new location.
5868 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005869 // accidentally created in the old location,
5870 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005871 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5872 if (oldFile.exists() && !databaseFile.exists()) {
5873 // Check for use directory; create if it doesn't exist, else renameTo will fail
5874 File userDir = Environment.getUserSystemDirectory(userId);
5875 if (!userDir.exists()) {
5876 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005877 throw new IllegalStateException(
5878 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005879 }
5880 }
5881 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005882 throw new IllegalStateException(
5883 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005884 }
5885 }
5886 }
5887 return databaseFile.getPath();
5888 }
5889
5890 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5891 return new AccountAuthenticatorCache(mContext);
5892 }
5893
5894 INotificationManager getNotificationManager() {
5895 return NotificationManager.getService();
5896 }
5897 }
Chris Wren717a8812017-03-31 15:34:39 -04005898
5899 private class NotificationId {
5900 final String mTag;
5901 private final int mId;
5902
5903 NotificationId(String tag, int type) {
5904 mTag = tag;
5905 mId = type;
5906 }
5907 }
Fred Quintana60307342009-03-24 22:48:12 -07005908}