blob: df292addb33f5d9fab293c76ceed6410505bfb1a [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;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050092import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080093import com.android.internal.util.ArrayUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080094import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -070095import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000096import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -070097import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060098import com.android.server.SystemService;
99
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700100import com.google.android.collect.Lists;
101import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700102
Oscar Montemayora8529f62009-11-18 10:14:20 -0800103import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700104import java.io.FileDescriptor;
105import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800106import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700107import java.security.MessageDigest;
108import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700109import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700110import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800111import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700112import java.util.Collection;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700113import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700114import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700115import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800116import java.util.LinkedHashMap;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800117import java.util.LinkedHashSet;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700118import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800119import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800120import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700121import java.util.Objects;
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700122import java.util.Set;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700123import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700124import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700125import java.util.concurrent.atomic.AtomicInteger;
126import 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 private final AtomicInteger mNotificationIds = new AtomicInteger(1);
194
Amith Yamasani04e0d262012-02-14 11:50:53 -0800195 static class UserAccounts {
196 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700197 final AccountsDb accountsDb;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800198 private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
199 credentialsPermissionNotificationIds =
200 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
201 private final HashMap<Account, Integer> signinRequiredNotificationIds =
202 new HashMap<Account, Integer>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700203 final Object cacheLock = new Object();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800204 /** protected by the {@link #cacheLock} */
Svet Ganov5d09c992016-09-07 09:57:41 -0700205 final HashMap<String, Account[]> accountCache =
Svet Ganovf6d424f12016-09-20 20:18:53 -0700206 new LinkedHashMap<>();
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>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800209 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700210 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700211 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700212 private final TokenCache accountTokenCaches = new TokenCache();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700213
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700214 /** protected by the {@link #mReceiversForType}
215 * 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;
240 synchronized (cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700241 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800242 }
243 }
244 }
245
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700246 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600247 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700248 // Not thread-safe. Only use in synchronized context
249 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700250 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
251 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800252
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700253 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700254 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700255
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700256 /**
257 * This should only be called by system code. One should only call this after the service
258 * has started.
259 * @return a reference to the AccountManagerService instance
260 * @hide
261 */
262 public static AccountManagerService getSingleton() {
263 return sThis.get();
264 }
Fred Quintana60307342009-03-24 22:48:12 -0700265
Fyodor Kupolovda993802016-09-21 14:47:10 -0700266 public AccountManagerService(Injector injector) {
267 mInjector = injector;
268 mContext = injector.getContext();
269 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700270 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700271 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
272 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800273 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700274
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700275 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800276
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800277 IntentFilter intentFilter = new IntentFilter();
278 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
279 intentFilter.addDataScheme("package");
280 mContext.registerReceiver(new BroadcastReceiver() {
281 @Override
282 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700283 // Don't delete accounts when updating a authenticator's
284 // package.
285 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700286 /* Purging data requires file io, don't block the main thread. This is probably
287 * less than ideal because we are introducing a race condition where old grants
288 * could be exercised until they are purged. But that race condition existed
289 * anyway with the broadcast receiver.
290 *
291 * Ideally, we would completely clear the cache, purge data from the database,
292 * and then rebuild the cache. All under the cache lock. But that change is too
293 * large at this point.
294 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800295 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700296 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700297 @Override
298 public void run() {
299 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800300 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800301 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700302 }
303 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700304 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700305 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800306 }
307 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800308
Fyodor Kupolovda993802016-09-21 14:47:10 -0700309 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700310
311 // Need to cancel account request notifications if the update/install can access the account
312 new PackageMonitor() {
313 @Override
314 public void onPackageAdded(String packageName, int uid) {
315 // Called on a handler, and running as the system
316 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
317 }
318
319 @Override
320 public void onPackageUpdateFinished(String packageName, int uid) {
321 // Called on a handler, and running as the system
322 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
323 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700324 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700325
326 // Cancel account request notification if an app op was preventing the account access
327 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
328 new AppOpsManager.OnOpChangedInternalListener() {
329 @Override
330 public void onOpChanged(int op, String packageName) {
331 try {
332 final int userId = ActivityManager.getCurrentUser();
333 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
334 final int mode = mAppOpsManager.checkOpNoThrow(
335 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
336 if (mode == AppOpsManager.MODE_ALLOWED) {
337 final long identity = Binder.clearCallingIdentity();
338 try {
339 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
340 } finally {
341 Binder.restoreCallingIdentity(identity);
342 }
343 }
344 } catch (NameNotFoundException e) {
345 /* ignore */
346 }
347 }
348 });
349
350 // Cancel account request notification if a permission was preventing the account access
351 mPackageManager.addOnPermissionsChangeListener(
352 (int uid) -> {
353 Account[] accounts = null;
354 String[] packageNames = mPackageManager.getPackagesForUid(uid);
355 if (packageNames != null) {
356 final int userId = UserHandle.getUserId(uid);
357 final long identity = Binder.clearCallingIdentity();
358 try {
359 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800360 // if app asked for permission we need to cancel notification even
361 // for O+ applications.
362 if (mPackageManager.checkPermission(
363 Manifest.permission.GET_ACCOUNTS,
364 packageName) != PackageManager.PERMISSION_GRANTED) {
365 continue;
366 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700367
368 if (accounts == null) {
369 accounts = getAccountsAsUser(null, userId, "android");
370 if (ArrayUtils.isEmpty(accounts)) {
371 return;
372 }
373 }
374
375 for (Account account : accounts) {
376 cancelAccountAccessRequestNotificationIfNeeded(
377 account, uid, packageName, true);
378 }
379 }
380 } finally {
381 Binder.restoreCallingIdentity(identity);
382 }
383 }
384 });
385 }
386
387 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
388 boolean checkAccess) {
389 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
390 for (Account account : accounts) {
391 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
392 }
393 }
394
395 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
396 boolean checkAccess) {
397 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
398 for (Account account : accounts) {
399 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
400 }
401 }
402
403 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
404 boolean checkAccess) {
405 String[] packageNames = mPackageManager.getPackagesForUid(uid);
406 if (packageNames != null) {
407 for (String packageName : packageNames) {
408 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
409 packageName, checkAccess);
410 }
411 }
412 }
413
414 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
415 int uid, String packageName, boolean checkAccess) {
416 if (!checkAccess || hasAccountAccess(account, packageName,
417 UserHandle.getUserHandleForUid(uid))) {
418 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700419 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700420 UserHandle.getUserHandleForUid(uid));
421 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800422 }
423
Dianne Hackborn164371f2013-10-01 19:10:13 -0700424 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800425 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800426 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800427 Bundle.setDefusable(extras, true);
428
429 final int callingUid = Binder.getCallingUid();
430 if (Log.isLoggable(TAG, Log.VERBOSE)) {
431 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
432 + ", pid " + Binder.getCallingPid());
433 }
434 Preconditions.checkNotNull(account, "account cannot be null");
435 int userId = UserHandle.getCallingUserId();
436 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
437 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
438 callingUid, account.type);
439 throw new SecurityException(msg);
440 }
441 /*
442 * Child users are not allowed to add accounts. Only the accounts that are shared by the
443 * parent profile can be added to child profile.
444 *
445 * TODO: Only allow accounts that were shared to be added by a limited user.
446 */
447 // fails if the account already exists
448 long identityToken = clearCallingIdentity();
449 try {
450 UserAccounts accounts = getUserAccounts(userId);
451 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800452 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800453 } finally {
454 restoreCallingIdentity(identityToken);
455 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700456 }
457
458 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800459 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
460 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800461 int callingUid = Binder.getCallingUid();
462 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
463 List<String> managedTypes =
464 getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
465
466 if ((accountType != null && !managedTypes.contains(accountType))
467 || (accountType == null && !isSystemUid)) {
468 throw new SecurityException(
469 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
470 + callingUid + " with packageName=" + packageName);
471 }
472 if (accountType != null) {
473 managedTypes = new ArrayList<String>();
474 managedTypes.add(accountType);
475 }
476
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800477 long identityToken = clearCallingIdentity();
478 try {
479 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
480 getUserAccounts(UserHandle.getUserId(callingUid)));
481 } finally {
482 restoreCallingIdentity(identityToken);
483 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800484 }
485
486 /*
487 * accountTypes may not be null
488 */
489 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
490 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
491 int uid = 0;
492 try {
493 uid = mPackageManager.getPackageUidAsUser(packageName,
494 UserHandle.getUserId(callingUid));
495 } catch (NameNotFoundException e) {
496 Log.d(TAG, "Package not found " + e.getMessage());
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800497 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800498 }
499
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800500 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800501 for (String accountType : accountTypes) {
502 synchronized (accounts.cacheLock) {
503 final Account[] accountsOfType = accounts.accountCache.get(accountType);
504 if (accountsOfType != null) {
505 for (Account account : accountsOfType) {
506 result.put(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800507 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800508 }
509 }
510 }
511 }
512 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800513 }
514
515 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800516 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700517 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700518 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800519 int userId = UserHandle.getUserId(callingUid);
520 UserAccounts accounts = getUserAccounts(userId);
521 if (!isAccountManagedByCaller(account.type, callingUid, userId)
522 && !isSystemUid(callingUid)) {
523 String msg =
524 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700525 throw new SecurityException(msg);
526 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800527 return getPackagesAndVisibilityForAccount(account, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800528 }
529
530 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800531 * Returns all package names and visibility values, which were set for given account.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800532 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800533 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800534 * @param accounts UserAccount that currently hosts the account and application
535 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800536 * @return Map from package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800537 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800538 private Map<String, Integer> getPackagesAndVisibilityForAccount(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800539 UserAccounts accounts) {
540 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
541 try {
542 return accounts.accountsDb.findAllVisibilityValuesForAccount(account);
543 } finally {
544 StrictMode.setThreadPolicy(oldPolicy);
545 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700546 }
547
548 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700549 public int getAccountVisibility(Account account, String packageName) {
550 Preconditions.checkNotNull(account, "account cannot be null");
551 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800552 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700553 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
554 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800555 && !isSystemUid(callingUid)) {
556 String msg = String.format(
557 "uid %s cannot get secrets for accounts of type: %s",
558 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700559 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800560 throw new SecurityException(msg);
561 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700562 return resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800563 }
564
565 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800566 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800567 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800568 * @param account The account to check visibility.
569 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800570 * @param accounts UserAccount that currently hosts the account and application
571 *
572 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
573 *
574 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800575 private int getAccountVisibility(Account account, String packageName, UserAccounts accounts) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800576 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
577 try {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700578 Integer visibility =
579 accounts.accountsDb.findAccountVisibility(account, packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800580 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
581 } finally {
582 StrictMode.setThreadPolicy(oldPolicy);
583 }
584 }
585
586 /**
587 * Method which handles default values for Account visibility.
588 *
589 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800590 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800591 * @param accounts UserAccount that currently hosts the account and application
592 *
593 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
594 *
595 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800596 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800597 UserAccounts accounts) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700598
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800599 Preconditions.checkNotNull(packageName, "packageName cannot be null");
600
601 int uid = -1;
602 try {
603 long identityToken = clearCallingIdentity();
604 try {
605 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
606 } finally {
607 restoreCallingIdentity(identityToken);
608 }
609 } catch (NameNotFoundException e) {
610 Log.d(TAG, "Package not found " + e.getMessage());
611 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800612 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800613
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800614 // System visibility can not be restricted.
615 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
616 return AccountManager.VISIBILITY_VISIBLE;
617 }
618
619 int signatureCheckResult =
620 checkPackageSignature(account.type, uid, accounts.userId);
621
622 // Authenticator can not restrict visibility to itself.
623 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
624 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
625 }
626
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800627 if (isSpecialPackageKey(packageName)) {
628 Log.d(TAG, "Package name is forbidden: " + packageName);
629 return AccountManager.VISIBILITY_NOT_VISIBLE;
630 }
631
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800632 // Return stored value if it was set.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800633 int visibility = getAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800634
635 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
636 return visibility;
637 }
638
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800639 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
640 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
641
642 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800643 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800644 return AccountManager.VISIBILITY_VISIBLE;
645 }
646 // Apps with READ_CONTACTS permission get visibility by default even post O.
647 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
648
649 boolean preO = isPreOApplication(packageName);
650 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
651 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800652 || canReadContacts || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800653 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
654 // match.
655 visibility = getAccountVisibility(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800656 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800657 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
658 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
659 }
660 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800661 visibility = getAccountVisibility(account,
662 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800663 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
664 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
665 }
666 }
667 return visibility;
668 }
669
670 /**
671 * Checks targetSdk for a package;
672 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800673 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800674 *
675 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
676 * undefined
677 */
678 private boolean isPreOApplication(String packageName) {
679 try {
680 long identityToken = clearCallingIdentity();
681 ApplicationInfo applicationInfo;
682 try {
683 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
684 } finally {
685 restoreCallingIdentity(identityToken);
686 }
687
688 if (applicationInfo != null) {
689 int version = applicationInfo.targetSdkVersion;
690 return version < android.os.Build.VERSION_CODES.O;
691 }
692 return true;
693 } catch (NameNotFoundException e) {
694 Log.d(TAG, "Package not found " + e.getMessage());
695 return true;
696 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800697 }
698
699 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700700 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
701 Preconditions.checkNotNull(account, "account cannot be null");
702 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800703 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700704 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
705 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800706 && !isSystemUid(callingUid)) {
707 String msg = String.format(
708 "uid %s cannot get secrets for accounts of type: %s",
709 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700710 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800711 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700712 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700713 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
714 accounts);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700715 }
716
717 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800718 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700719 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800720 * @param account Account to update visibility.
721 * @param packageName Package name for which visibility is updated.
722 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800723 * @param notify if the flag is set applications will get notification about visibility change
724 * @param accounts UserAccount that currently hosts the account and application
725 *
726 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700727 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800728 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800729 boolean notify, UserAccounts accounts) {
730 synchronized (accounts.cacheLock) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700731 Map<String, Integer> packagesToVisibility;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800732 if (notify) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800733 if (isSpecialPackageKey(packageName)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700734 packagesToVisibility =
735 getRequestingPackages(account, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800736 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800737 if (!packageExistsForUser(packageName, accounts.userId)) {
738 return false; // package is not installed.
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100739 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700740 packagesToVisibility = new HashMap<>();
741 packagesToVisibility.put(packageName,
742 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800743 }
744 } else {
745 // Notifications will not be send.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800746 if (!isSpecialPackageKey(packageName) &&
747 !packageExistsForUser(packageName, accounts.userId)) {
748 // package is not installed and not meta value.
749 return false;
750 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700751 packagesToVisibility = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800752 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800753
754 final long accountId = accounts.accountsDb.findDeAccountId(account);
755 if (accountId < 0) {
756 return false;
757 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800758
759 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
760 try {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800761 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
762 newVisibility)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800763 return false;
764 }
765 } finally {
766 StrictMode.setThreadPolicy(oldPolicy);
767 }
768
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800769 if (notify) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700770 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
771 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
772 notifyPackage(packageToVisibility.getKey(), accounts);
773 }
774 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800775 sendAccountsChangedBroadcast(accounts.userId);
776 }
777 return true;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700778 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700779 }
780
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700781 @Override
782 public void registerAccountListener(String[] accountTypes, String opPackageName) {
783 int callingUid = Binder.getCallingUid();
784 mAppOpsManager.checkPackage(callingUid, opPackageName);
785 registerAccountListener(accountTypes, opPackageName,
786 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800787 }
788
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700789 private void registerAccountListener(String[] accountTypes, String opPackageName,
790 UserAccounts accounts) {
791 synchronized (accounts.mReceiversForType) {
792 if (accountTypes == null) {
793 // null for any type
794 accountTypes = new String[] {null};
795 }
796 for (String type : accountTypes) {
797 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
798 if (receivers == null) {
799 receivers = new HashMap<>();
800 accounts.mReceiversForType.put(type, receivers);
801 }
802 Integer cnt = receivers.get(opPackageName);
803 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800804 }
805 }
806 }
807
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700808 @Override
809 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
810 int callingUid = Binder.getCallingUid();
811 mAppOpsManager.checkPackage(callingUid, opPackageName);
812 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
813 synchronized (accounts.mReceiversForType) {
814 if (accountTypes == null) {
815 // null for any type
816 accountTypes = new String[] {null};
817 }
818 for (String type : accountTypes) {
819 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
820 if (receivers == null || receivers.get(opPackageName) == null) {
821 throw new IllegalArgumentException("attempt to unregister wrong receiver");
822 }
823 Integer cnt = receivers.get(opPackageName);
824 if (cnt == 1) {
825 receivers.remove(opPackageName);
826 } else {
827 receivers.put(opPackageName, cnt - 1);
828 }
829 }
830 }
831 }
832
833 // Send notification to all packages which can potentially see the account
834 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
835 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
836 // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
837 // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
838 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
839 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
840 notifyPackage(packageToVisibility.getKey(), accounts);
841 }
842 }
843 }
844
845 /**
846 * Sends a direct intent to a package, notifying it of account visibility change.
847 *
848 * @param packageName to send Account to
849 * @param accounts UserAccount that currently hosts the account
850 */
851 private void notifyPackage(String packageName, UserAccounts accounts) {
852 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
853 intent.setPackage(packageName);
854 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
855 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
856 }
857
858 // Returns a map from package name to visibility, for packages subscribed
859 // to notifications about any account type, or type of provided account
860 // account type or all types.
861 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
862 Set<String> packages = new HashSet<>();
863 synchronized (accounts.mReceiversForType) {
864 for (String type : new String[] {account.type, null}) {
865 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
866 if (receivers != null) {
867 packages.addAll(receivers.keySet());
868 }
869 }
870 }
871 Map<String, Integer> result = new HashMap<>();
872 for (String packageName : packages) {
873 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
874 }
875 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800876 }
877
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800878 private boolean packageExistsForUser(String packageName, int userId) {
879 try {
880 long identityToken = clearCallingIdentity();
881 try {
882 mPackageManager.getPackageUidAsUser(packageName, userId);
883 return true; // package exist
884 } finally {
885 restoreCallingIdentity(identityToken);
886 }
887 } catch (NameNotFoundException e) {
888 return false;
889 }
890 }
891
892 /**
893 * Returns true if packageName is one of special values.
894 */
895 private boolean isSpecialPackageKey(String packageName) {
896 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
897 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
898 }
899
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800900 private void sendAccountsChangedBroadcast(int userId) {
901 Log.i(TAG, "the accounts changed, sending broadcast of "
902 + ACCOUNTS_CHANGED_INTENT.getAction());
903 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700904 }
905
906 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700907 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
908 throws RemoteException {
909 try {
910 return super.onTransact(code, data, reply, flags);
911 } catch (RuntimeException e) {
912 // The account manager only throws security exceptions, so let's
913 // log all others.
914 if (!(e instanceof SecurityException)) {
915 Slog.wtf(TAG, "Account Manager Crash", e);
916 }
917 throw e;
918 }
919 }
920
Amith Yamasani258848d2012-08-10 17:06:33 -0700921 private UserManager getUserManager() {
922 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700923 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700924 }
925 return mUserManager;
926 }
927
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700928 /**
929 * Validate internal set of accounts against installed authenticators for
930 * given user. Clears cached authenticators before validating.
931 */
932 public void validateAccounts(int userId) {
933 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700934 // Invalidate user-specific cache to make sure we catch any
935 // removed authenticators.
936 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
937 }
938
939 /**
940 * Validate internal set of accounts against installed authenticators for
941 * given user. Clear cached authenticators before validating when requested.
942 */
943 private void validateAccountsInternal(
944 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700945 if (Log.isLoggable(TAG, Log.DEBUG)) {
946 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700947 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600948 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700949 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700950
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700951 if (invalidateAuthenticatorCache) {
952 mAuthenticatorCache.invalidateCache(accounts.userId);
953 }
954
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700955 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
956 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700957 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700958
Amith Yamasani04e0d262012-02-14 11:50:53 -0800959 synchronized (accounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800960 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800961
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700962 // Get a map of stored authenticator types to UID
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700963 final AccountsDb accountsDb = accounts.accountsDb;
964 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800965 // Create a list of authenticator type whose previous uid no longer exists
966 HashSet<String> obsoleteAuthType = Sets.newHashSet();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700967 SparseBooleanArray knownUids = null;
968 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
969 String type = authToUidEntry.getKey();
970 int uid = authToUidEntry.getValue();
971 Integer knownUid = knownAuth.get(type);
972 if (knownUid != null && uid == knownUid) {
973 // Remove it from the knownAuth list if it's unchanged.
974 knownAuth.remove(type);
975 } else {
976 /*
977 * The authenticator is presently not cached and should only be triggered
978 * when we think an authenticator has been removed (or is being updated).
979 * But we still want to check if any data with the associated uid is
980 * around. This is an (imperfect) signal that the package may be updating.
981 *
982 * A side effect of this is that an authenticator sharing a uid with
983 * multiple apps won't get its credentials wiped as long as some app with
984 * that uid is still on the device. But I suspect that this is a rare case.
985 * And it isn't clear to me how an attacker could really exploit that
986 * feature.
987 *
988 * The upshot is that we don't have to worry about accounts getting
989 * uninstalled while the authenticator's package is being updated.
990 *
991 */
992 if (knownUids == null) {
993 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800994 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700995 if (!knownUids.get(uid)) {
996 // The authenticator is not presently available to the cache. And the
997 // package no longer has a data directory (so we surmise it isn't updating).
998 // So purge its data from the account databases.
999 obsoleteAuthType.add(type);
1000 // And delete it from the TABLE_META
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001001 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001002 }
1003 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001004 }
1005
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001006 // Add the newly registered authenticator to TABLE_META. If old authenticators have
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001007 // been re-enabled (after being updated for example), then we just overwrite the old
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001008 // values.
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001009 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001010 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001011 }
1012
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001013 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001014 try {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001015 accounts.accountCache.clear();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001016 final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001017 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1018 final long accountId = accountEntry.getKey();
1019 final Account account = accountEntry.getValue();
1020 if (obsoleteAuthType.contains(account.type)) {
1021 Slog.w(TAG, "deleting account " + account.name + " because type "
1022 + account.type + "'s registered authenticator no longer exist.");
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001023 Map<String, Integer> packagesToVisibility =
1024 getRequestingPackages(account, accounts);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001025 accountsDb.beginTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001026 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001027 accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001028 // Also delete from CE table if user is unlocked; if user is currently
1029 // locked the account will be removed later by syncDeCeAccountsLocked
1030 if (userUnlocked) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001031 accountsDb.deleteCeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001032 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001033 accountsDb.setTransactionSuccessful();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001034 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001035 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001036 }
Fred Quintana56285a62010-12-02 14:20:51 -08001037 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001038
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001039 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1040 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001041
Amith Yamasani04e0d262012-02-14 11:50:53 -08001042 accounts.userDataCache.remove(account);
1043 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07001044 accounts.accountTokenCaches.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001045
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001046 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
1047 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
1048 notifyPackage(packageToVisibility.getKey(), accounts);
1049 }
1050 }
Fred Quintana56285a62010-12-02 14:20:51 -08001051 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001052 ArrayList<String> accountNames = accountNamesByType.get(account.type);
Fred Quintana56285a62010-12-02 14:20:51 -08001053 if (accountNames == null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001054 accountNames = new ArrayList<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001055 accountNamesByType.put(account.type, accountNames);
Fred Quintana56285a62010-12-02 14:20:51 -08001056 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001057 accountNames.add(account.name);
Fred Quintana56285a62010-12-02 14:20:51 -08001058 }
1059 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001060 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
Fred Quintana56285a62010-12-02 14:20:51 -08001061 final String accountType = cur.getKey();
1062 final ArrayList<String> accountNames = cur.getValue();
1063 final Account[] accountsForType = new Account[accountNames.size()];
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001064 for (int i = 0; i < accountsForType.length; i++) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07001065 accountsForType[i] = new Account(accountNames.get(i), accountType,
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001066 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001067 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001068 accounts.accountCache.put(accountType, accountsForType);
Fred Quintanaafa92b82009-12-01 16:27:03 -08001069 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001070 } finally {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001071 if (accountDeleted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001072 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001073 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001074 }
1075 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001076 }
1077
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001078 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1079 // Get the UIDs of all apps that might have data on the device. We want
1080 // to preserve user data if the app might otherwise be storing data.
1081 List<PackageInfo> pkgsWithData =
1082 mPackageManager.getInstalledPackagesAsUser(
1083 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1084 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1085 for (PackageInfo pkgInfo : pkgsWithData) {
1086 if (pkgInfo.applicationInfo != null
1087 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1088 knownUids.put(pkgInfo.applicationInfo.uid, true);
1089 }
1090 }
1091 return knownUids;
1092 }
1093
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001094 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001095 Context context,
1096 int userId) {
1097 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001098 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1099 }
1100
1101 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1102 IAccountAuthenticatorCache authCache,
1103 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001104 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001105 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1106 .getAllServices(userId)) {
1107 knownAuth.put(service.type.type, service.uid);
1108 }
1109 return knownAuth;
1110 }
1111
Amith Yamasani04e0d262012-02-14 11:50:53 -08001112 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001113 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001114 }
1115
1116 protected UserAccounts getUserAccounts(int userId) {
1117 synchronized (mUsers) {
1118 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001119 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001120 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001121 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1122 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001123 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001124 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001125 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001126 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001127 validateAccounts = true;
1128 }
1129 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001130 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001131 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
1132 synchronized (accounts.cacheLock) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001133 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001134 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001135 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001136 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001137 }
1138 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001139 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001140 }
1141 return accounts;
1142 }
1143 }
1144
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001145 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1146 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001147 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001148 if (!accountsToRemove.isEmpty()) {
1149 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1150 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001151 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1152 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001153
1154 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001155 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001156 }
1157 }
1158 }
1159
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001160 private void purgeOldGrantsAll() {
1161 synchronized (mUsers) {
1162 for (int i = 0; i < mUsers.size(); i++) {
1163 purgeOldGrants(mUsers.valueAt(i));
1164 }
1165 }
1166 }
1167
1168 private void purgeOldGrants(UserAccounts accounts) {
1169 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001170 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001171 for (int uid : uids) {
1172 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1173 if (packageExists) {
1174 continue;
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001175 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001176 Log.d(TAG, "deleting grants for UID " + uid
1177 + " because its package is no longer installed");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001178 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001179 }
1180 }
1181 }
1182
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001183 private void removeVisibilityValuesForPackage(String packageName) {
1184 synchronized (mUsers) {
1185 for (int i = 0; i < mUsers.size(); i++) {
1186 UserAccounts accounts = mUsers.valueAt(i);
1187 try {
1188 int uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1189 } catch (NameNotFoundException e) {
1190 // package does not exist - remove visibility values
1191 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
1192 }
1193 }
1194 }
1195 }
1196
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -07001197 private void onCleanupUser(int userId) {
1198 Log.i(TAG, "onCleanupUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001199 UserAccounts accounts;
1200 synchronized (mUsers) {
1201 accounts = mUsers.get(userId);
1202 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001203 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001204 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001205 if (accounts != null) {
1206 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001207 accounts.accountsDb.close();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001208 }
Amith Yamasani13593602012-03-22 16:16:17 -07001209 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001210 }
1211
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001212 @VisibleForTesting
1213 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001214 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1215 }
1216
1217 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001218 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1219 Log.v(TAG, "onUserUnlocked " + userId);
1220 }
1221 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001222 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001223 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001224 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001225 syncSharedAccounts(userId);
1226 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001227
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001228 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001229 // Check if there's a shared account that needs to be created as an account
1230 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1231 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001232 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001233 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001234 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001235 : UserHandle.USER_SYSTEM;
1236 if (parentUserId < 0) {
1237 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1238 return;
1239 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001240 for (Account sa : sharedAccounts) {
1241 if (ArrayUtils.contains(accounts, sa)) continue;
1242 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001243 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001244 }
1245 }
1246
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001247 @Override
1248 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001249 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001250 }
1251
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001252 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001253 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001254 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001255 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1256 Log.v(TAG, "getPassword: " + account
1257 + ", caller's uid " + Binder.getCallingUid()
1258 + ", pid " + Binder.getCallingPid());
1259 }
Fred Quintana382601f2010-03-25 12:25:10 -07001260 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001261 int userId = UserHandle.getCallingUserId();
1262 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001263 String msg = String.format(
1264 "uid %s cannot get secrets for accounts of type: %s",
1265 callingUid,
1266 account.type);
1267 throw new SecurityException(msg);
1268 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001269 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001270 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001271 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001272 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001273 } finally {
1274 restoreCallingIdentity(identityToken);
1275 }
1276 }
1277
Amith Yamasani04e0d262012-02-14 11:50:53 -08001278 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001279 if (account == null) {
1280 return null;
1281 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001282 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001283 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1284 return null;
1285 }
Fred Quintana31957f12009-10-21 13:43:10 -07001286
Amith Yamasani04e0d262012-02-14 11:50:53 -08001287 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001288 return accounts.accountsDb.findAccountPasswordByNameAndType(account.name, account.type);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001289 }
1290 }
1291
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001292 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001293 public String getPreviousName(Account account) {
1294 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1295 Log.v(TAG, "getPreviousName: " + account
1296 + ", caller's uid " + Binder.getCallingUid()
1297 + ", pid " + Binder.getCallingPid());
1298 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001299 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001300 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001301 long identityToken = clearCallingIdentity();
1302 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001303 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001304 return readPreviousNameInternal(accounts, account);
1305 } finally {
1306 restoreCallingIdentity(identityToken);
1307 }
1308 }
1309
1310 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1311 if (account == null) {
1312 return null;
1313 }
1314 synchronized (accounts.cacheLock) {
1315 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1316 if (previousNameRef == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001317 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001318 previousNameRef = new AtomicReference<>(previousName);
1319 accounts.previousNameCache.put(account, previousNameRef);
1320 return previousName;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001321 } else {
1322 return previousNameRef.get();
1323 }
1324 }
1325 }
1326
1327 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001328 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001329 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001330 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001331 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1332 account, key, callingUid, Binder.getCallingPid());
1333 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001334 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001335 Preconditions.checkNotNull(account, "account cannot be null");
1336 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001337 int userId = UserHandle.getCallingUserId();
1338 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001339 String msg = String.format(
1340 "uid %s cannot get user data for accounts of type: %s",
1341 callingUid,
1342 account.type);
1343 throw new SecurityException(msg);
1344 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001345 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001346 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1347 return null;
1348 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001349 long identityToken = clearCallingIdentity();
1350 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001351 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00001352 synchronized (accounts.cacheLock) {
1353 if (!accountExistsCacheLocked(accounts, account)) {
1354 return null;
1355 }
1356 return readUserDataInternalLocked(accounts, account, key);
1357 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001358 } finally {
1359 restoreCallingIdentity(identityToken);
1360 }
1361 }
1362
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001363 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001364 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001365 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001366 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1367 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001368 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001369 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001370 + ", pid " + Binder.getCallingPid());
1371 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001372 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001373 if (isCrossUser(callingUid, userId)) {
1374 throw new SecurityException(
1375 String.format(
1376 "User %s tying to get authenticator types for %s" ,
1377 UserHandle.getCallingUserId(),
1378 userId));
1379 }
1380
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001381 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001382 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001383 return getAuthenticatorTypesInternal(userId);
1384
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001385 } finally {
1386 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001387 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001388 }
1389
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001390 /**
1391 * Should only be called inside of a clearCallingIdentity block.
1392 */
1393 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001394 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001395 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1396 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1397 AuthenticatorDescription[] types =
1398 new AuthenticatorDescription[authenticatorCollection.size()];
1399 int i = 0;
1400 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1401 : authenticatorCollection) {
1402 types[i] = authenticator.type;
1403 i++;
1404 }
1405 return types;
1406 }
1407
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001408 private boolean isCrossUser(int callingUid, int userId) {
1409 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001410 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001411 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001412 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1413 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001414 }
1415
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001416 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001417 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001418 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001419 }
1420
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001421 @Override
1422 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001423 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001424 int callingUid = Binder.getCallingUid();
1425 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1426 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001427 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001428 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001429 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1430 final UserAccounts toAccounts = getUserAccounts(userTo);
1431 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001432 if (response != null) {
1433 Bundle result = new Bundle();
1434 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1435 try {
1436 response.onResult(result);
1437 } catch (RemoteException e) {
1438 Slog.w(TAG, "Failed to report error back to the client." + e);
1439 }
1440 }
1441 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001442 }
1443
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001444 Slog.d(TAG, "Copying account " + account.name
1445 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001446 long identityToken = clearCallingIdentity();
1447 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001448 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001449 false /* stripAuthTokenFromResult */, account.name,
1450 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001451 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001452 protected String toDebugString(long now) {
1453 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1454 + ", " + account.type;
1455 }
1456
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001457 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001458 public void run() throws RemoteException {
1459 mAuthenticator.getAccountCredentialsForCloning(this, account);
1460 }
1461
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001462 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001463 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001464 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001465 if (result != null
1466 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1467 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001468 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001469 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001470 super.onResult(result);
1471 }
1472 }
1473 }.bind();
1474 } finally {
1475 restoreCallingIdentity(identityToken);
1476 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001477 }
1478
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001479 @Override
1480 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001481 final int callingUid = Binder.getCallingUid();
1482 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1483 String msg = String.format(
1484 "accountAuthenticated( account: %s, callerUid: %s)",
1485 account,
1486 callingUid);
1487 Log.v(TAG, msg);
1488 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001489 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001490 int userId = UserHandle.getCallingUserId();
1491 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001492 String msg = String.format(
1493 "uid %s cannot notify authentication for accounts of type: %s",
1494 callingUid,
1495 account.type);
1496 throw new SecurityException(msg);
1497 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001498
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001499 if (!canUserModifyAccounts(userId, callingUid) ||
1500 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001501 return false;
1502 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001503
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001504 long identityToken = clearCallingIdentity();
1505 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001506 UserAccounts accounts = getUserAccounts(userId);
1507 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001508 } finally {
1509 restoreCallingIdentity(identityToken);
1510 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001511 }
1512
1513 private boolean updateLastAuthenticatedTime(Account account) {
1514 final UserAccounts accounts = getUserAccountsForCaller();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001515 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001516 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001517 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001518 }
1519
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001520 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001521 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1522 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001523 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001524 long id = clearCallingIdentity();
1525 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001526 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001527 false /* stripAuthTokenFromResult */, account.name,
1528 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001529 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001530 protected String toDebugString(long now) {
1531 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1532 + ", " + account.type;
1533 }
1534
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001535 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001536 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001537 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001538 UserAccounts owner = getUserAccounts(parentUserId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001539 synchronized (owner.cacheLock) {
Svetoslavf3f02ac2015-09-08 14:36:35 -07001540 for (Account acc : getAccounts(parentUserId,
1541 mContext.getOpPackageName())) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001542 if (acc.equals(account)) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001543 mAuthenticator.addAccountFromCredentials(
1544 this, account, accountCredentials);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001545 break;
1546 }
1547 }
1548 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001549 }
1550
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001551 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001552 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001553 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001554 // TODO: Anything to do if if succedded?
1555 // TODO: If it failed: Show error notification? Should we remove the shadow
1556 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001557 // TODO: what we do with the visibility?
1558
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001559 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001560 }
1561
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001562 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001563 public void onError(int errorCode, String errorMessage) {
1564 super.onError(errorCode, errorMessage);
1565 // TODO: Show error notification to user
1566 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1567 }
1568
1569 }.bind();
1570 } finally {
1571 restoreCallingIdentity(id);
1572 }
1573 }
1574
Amith Yamasani04e0d262012-02-14 11:50:53 -08001575 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001576 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001577 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001578 if (account == null) {
1579 return false;
1580 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001581 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001582 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1583 + " is locked. callingUid=" + callingUid);
1584 return false;
1585 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001586 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001587 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001588 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001589 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001590 Log.w(TAG, "insertAccountIntoDatabase: " + account
1591 + ", skipping since the account already exists");
1592 return false;
1593 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001594 long accountId = accounts.accountsDb.insertCeAccount(account, password);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001595 if (accountId < 0) {
1596 Log.w(TAG, "insertAccountIntoDatabase: " + account
1597 + ", skipping the DB insert failed");
1598 return false;
1599 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001600 // Insert into DE table
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001601 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001602 Log.w(TAG, "insertAccountIntoDatabase: " + account
1603 + ", skipping the DB insert failed");
1604 return false;
1605 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001606 if (extras != null) {
1607 for (String key : extras.keySet()) {
1608 final String value = extras.getString(key);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001609 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001610 Log.w(TAG, "insertAccountIntoDatabase: " + account
1611 + ", skipping since insertExtra failed for key " + key);
1612 return false;
1613 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001614 }
1615 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001616
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001617 if (packageToVisibility != null) {
1618 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1619 setAccountVisibility(account, entry.getKey() /* package */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001620 entry.getValue() /* visibility */, false /* notify */, accounts);
1621 }
1622 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001623 accounts.accountsDb.setTransactionSuccessful();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001624
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001625 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
1626 accounts, callingUid);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001627
Amith Yamasani04e0d262012-02-14 11:50:53 -08001628 insertAccountIntoCacheLocked(accounts, account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001629 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001630 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001631 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001632 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001633 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1634 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001635 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001636
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001637 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001638 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1639 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001640
Amith Yamasani5be347b2013-03-31 17:44:31 -07001641 return true;
1642 }
1643
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001644 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001645 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001646 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001647 }
1648 }
1649
Amith Yamasani5be347b2013-03-31 17:44:31 -07001650 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001651 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001652 * running, then clone the account too.
1653 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001654 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001655 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001656 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001657 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001658 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001659 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001660 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001661 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001662 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001663 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001664 }
1665 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001666 }
1667 }
1668
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001669 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001670 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001671 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001672 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001673 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001674 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1675 Log.v(TAG, "hasFeatures: " + account
1676 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001677 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001678 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001679 + ", pid " + Binder.getCallingPid());
1680 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001681 Preconditions.checkArgument(account != null, "account cannot be null");
1682 Preconditions.checkArgument(response != null, "response cannot be null");
1683 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001684 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001685 checkReadAccountsPermitted(callingUid, account.type, userId,
1686 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001687
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001688 long identityToken = clearCallingIdentity();
1689 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001690 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001691 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001692 } finally {
1693 restoreCallingIdentity(identityToken);
1694 }
1695 }
1696
1697 private class TestFeaturesSession extends Session {
1698 private final String[] mFeatures;
1699 private final Account mAccount;
1700
Amith Yamasani04e0d262012-02-14 11:50:53 -08001701 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001702 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001703 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001704 true /* stripAuthTokenFromResult */, account.name,
1705 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001706 mFeatures = features;
1707 mAccount = account;
1708 }
1709
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001710 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001711 public void run() throws RemoteException {
1712 try {
1713 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1714 } catch (RemoteException e) {
1715 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1716 }
1717 }
1718
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001719 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001720 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001721 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001722 IAccountManagerResponse response = getResponseAndClose();
1723 if (response != null) {
1724 try {
1725 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001726 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001727 return;
1728 }
Fred Quintana56285a62010-12-02 14:20:51 -08001729 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1730 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1731 + response);
1732 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001733 final Bundle newResult = new Bundle();
1734 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1735 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1736 response.onResult(newResult);
1737 } catch (RemoteException e) {
1738 // if the caller is dead then there is no one to care about remote exceptions
1739 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1740 Log.v(TAG, "failure while notifying response", e);
1741 }
1742 }
1743 }
1744 }
1745
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001746 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001747 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001748 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001749 + ", " + mAccount
1750 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1751 }
1752 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001753
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001754 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001755 public void renameAccount(
1756 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001757 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001758 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1759 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001760 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001761 + ", pid " + Binder.getCallingPid());
1762 }
1763 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001764 int userId = UserHandle.getCallingUserId();
1765 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001766 String msg = String.format(
1767 "uid %s cannot rename accounts of type: %s",
1768 callingUid,
1769 accountToRename.type);
1770 throw new SecurityException(msg);
1771 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001772 long identityToken = clearCallingIdentity();
1773 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001774 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001775 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001776 Bundle result = new Bundle();
1777 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1778 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001779 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1780 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001781 try {
1782 response.onResult(result);
1783 } catch (RemoteException e) {
1784 Log.w(TAG, e.getMessage());
1785 }
1786 } finally {
1787 restoreCallingIdentity(identityToken);
1788 }
1789 }
1790
1791 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001792 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001793 Account resultAccount = null;
1794 /*
1795 * Cancel existing notifications. Let authenticators
1796 * re-post notifications as required. But we don't know if
1797 * the authenticators have bound their notifications to
1798 * now stale account name data.
1799 *
1800 * With a rename api, we might not need to do this anymore but it
1801 * shouldn't hurt.
1802 */
1803 cancelNotification(
1804 getSigninRequiredNotificationId(accounts, accountToRename),
1805 new UserHandle(accounts.userId));
1806 synchronized(accounts.credentialsPermissionNotificationIds) {
1807 for (Pair<Pair<Account, String>, Integer> pair:
1808 accounts.credentialsPermissionNotificationIds.keySet()) {
1809 if (accountToRename.equals(pair.first.first)) {
1810 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1811 cancelNotification(id, new UserHandle(accounts.userId));
1812 }
1813 }
1814 }
1815 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001816 accounts.accountsDb.beginTransaction();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001817 Account renamedAccount = new Account(newName, accountToRename.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001818 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1819 Log.e(TAG, "renameAccount failed - account with new name already exists");
1820 return null;
1821 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001822 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001823 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001824 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001825 accounts.accountsDb.renameCeAccount(accountId, newName);
Dmitry Dementyevcf50dcf2016-11-17 14:14:11 -08001826 if (accounts.accountsDb.renameDeAccount(
1827 accountId, newName, accountToRename.name)) {
1828 accounts.accountsDb.setTransactionSuccessful();
1829 } else {
1830 Log.e(TAG, "renameAccount failed");
1831 return null;
1832 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001833 } else {
1834 Log.e(TAG, "renameAccount failed - old account does not exist");
1835 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001836 }
1837 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001838 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001839 }
1840 /*
1841 * Database transaction was successful. Clean up cached
1842 * data associated with the account in the user profile.
1843 */
Svet Ganov5c4a5122016-09-23 19:29:11 -07001844 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001845 /*
1846 * Extract the data and token caches before removing the
1847 * old account to preserve the user data associated with
1848 * the account.
1849 */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001850 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1851 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001852 removeAccountFromCacheLocked(accounts, accountToRename);
1853 /*
1854 * Update the cached data associated with the renamed
1855 * account.
1856 */
1857 accounts.userDataCache.put(renamedAccount, tmpData);
1858 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1859 accounts.previousNameCache.put(
1860 renamedAccount,
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001861 new AtomicReference<>(accountToRename.name));
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001862 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001863
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001864 int parentUserId = accounts.userId;
1865 if (canHaveProfile(parentUserId)) {
1866 /*
1867 * Owner or system user account was renamed, rename the account for
1868 * those users with which the account was shared.
1869 */
1870 List<UserInfo> users = getUserManager().getUsers(true);
1871 for (UserInfo user : users) {
1872 if (user.isRestricted()
1873 && (user.restrictedProfileParentId == parentUserId)) {
1874 renameSharedAccountAsUser(accountToRename, newName, user.id);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001875 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001876 }
1877 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001878
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001879 sendNotificationAccountUpdated(resultAccount, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001880 sendAccountsChangedBroadcast(accounts.userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001881 }
1882 return resultAccount;
1883 }
1884
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001885 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001886 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001887 return userInfo != null && userInfo.canHaveProfile();
1888 }
1889
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001890 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001891 public void removeAccount(IAccountManagerResponse response, Account account,
1892 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001893 removeAccountAsUser(
1894 response,
1895 account,
1896 expectActivityLaunch,
1897 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001898 }
1899
1900 @Override
1901 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001902 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001903 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001904 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1905 Log.v(TAG, "removeAccount: " + account
1906 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001907 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001908 + ", pid " + Binder.getCallingPid()
1909 + ", for user id " + userId);
1910 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001911 Preconditions.checkArgument(account != null, "account cannot be null");
1912 Preconditions.checkArgument(response != null, "response cannot be null");
1913
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001914 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001915 if (isCrossUser(callingUid, userId)) {
1916 throw new SecurityException(
1917 String.format(
1918 "User %s tying remove account for %s" ,
1919 UserHandle.getCallingUserId(),
1920 userId));
1921 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001922 /*
1923 * Only the system or authenticator should be allowed to remove accounts for that
1924 * authenticator. This will let users remove accounts (via Settings in the system) but not
1925 * arbitrary applications (like competing authenticators).
1926 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001927 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00001928 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1929 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001930 String msg = String.format(
1931 "uid %s cannot remove accounts of type: %s",
1932 callingUid,
1933 account.type);
1934 throw new SecurityException(msg);
1935 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001936 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001937 try {
1938 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
1939 "User cannot modify accounts");
1940 } catch (RemoteException re) {
1941 }
1942 return;
1943 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001944 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001945 try {
1946 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
1947 "User cannot modify accounts of this type (policy).");
1948 } catch (RemoteException re) {
1949 }
1950 return;
1951 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001952 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001953 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001954 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001955 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001956 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08001957 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001958 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001959 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001960 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001961 }
1962 }
1963 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001964 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001965 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001966 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1967 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001968 accountId,
1969 accounts,
1970 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001971 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001972 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
1973 } finally {
1974 restoreCallingIdentity(identityToken);
1975 }
1976 }
1977
1978 @Override
1979 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001980 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001981 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1982 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001983 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001984 + ", pid " + Binder.getCallingPid());
1985 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001986 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001987 if (account == null) {
1988 /*
1989 * Null accounts should result in returning false, as per
1990 * AccountManage.addAccountExplicitly(...) java doc.
1991 */
1992 Log.e(TAG, "account is null");
1993 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001994 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001995 String msg = String.format(
1996 "uid %s cannot explicitly add accounts of type: %s",
1997 callingUid,
1998 account.type);
1999 throw new SecurityException(msg);
2000 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002001 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002002 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002003 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002004 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2005 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002006 accountId,
2007 accounts,
2008 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002009 long identityToken = clearCallingIdentity();
2010 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002011 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002012 } finally {
2013 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002014 }
Fred Quintana60307342009-03-24 22:48:12 -07002015 }
2016
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002017 private class RemoveAccountSession extends Session {
2018 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002019 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002020 Account account, boolean expectActivityLaunch) {
2021 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002022 true /* stripAuthTokenFromResult */, account.name,
2023 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002024 mAccount = account;
2025 }
2026
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002027 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002028 protected String toDebugString(long now) {
2029 return super.toDebugString(now) + ", removeAccount"
2030 + ", account " + mAccount;
2031 }
2032
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002033 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002034 public void run() throws RemoteException {
2035 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2036 }
2037
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002038 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002039 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002040 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002041 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2042 && !result.containsKey(AccountManager.KEY_INTENT)) {
2043 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002044 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002045 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002046 }
2047 IAccountManagerResponse response = getResponseAndClose();
2048 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002049 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2050 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2051 + response);
2052 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002053 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002054 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002055 try {
2056 response.onResult(result2);
2057 } catch (RemoteException e) {
2058 // ignore
2059 }
2060 }
2061 }
2062 super.onResult(result);
2063 }
2064 }
2065
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002066 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002067 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002068 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002069 }
2070
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002071 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002072 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002073 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002074 if (!userUnlocked) {
2075 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2076 + " is still locked. CE data will be removed later");
2077 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08002078 synchronized (accounts.cacheLock) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002079 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002080 accounts.accountsDb.beginTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002081 // Set to a dummy value, this will only be used if the database
2082 // transaction succeeds.
2083 long accountId = -1;
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002084 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002085 accountId = accounts.accountsDb.findDeAccountId(account);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002086 if (accountId >= 0) {
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002087 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002088 }
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002089 // always delete from CE table if CE storage is available
2090 // DE account could be removed while CE was locked
2091 if (userUnlocked) {
2092 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2093 if (ceAccountId >= 0) {
2094 accounts.accountsDb.deleteCeAccount(ceAccountId);
2095 }
2096 }
2097 accounts.accountsDb.setTransactionSuccessful();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002098 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002099 accounts.accountsDb.endTransaction();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002100 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002101 if (isChanged) {
2102 removeAccountFromCacheLocked(accounts, account);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002103 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
2104 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
2105 notifyPackage(packageToVisibility.getKey(), accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002106 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002107 }
2108
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002109 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002110 sendAccountsChangedBroadcast(accounts.userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002111 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2112 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2113 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002114 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002115 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002116 long id = Binder.clearCallingIdentity();
2117 try {
2118 int parentUserId = accounts.userId;
2119 if (canHaveProfile(parentUserId)) {
2120 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002121 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002122 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002123 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002124 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002125 }
2126 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002127 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002128 } finally {
2129 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002130 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002131
2132 if (isChanged) {
2133 synchronized (accounts.credentialsPermissionNotificationIds) {
2134 for (Pair<Pair<Account, String>, Integer> key
2135 : accounts.credentialsPermissionNotificationIds.keySet()) {
2136 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002137 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002138 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002139 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002140 account, uid, false));
2141 }
2142 }
2143 }
2144 }
2145
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002146 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002147 }
2148
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002149 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002150 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002151 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002152 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2153 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002154 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2155 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002156 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002157 + ", pid " + Binder.getCallingPid());
2158 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002159 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002160 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002161 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002162 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002163 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002164 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002165 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002166 invalidateAuthTokenLocked(accounts, accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002167 invalidateCustomTokenLocked(accounts, accountType, authToken);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002168 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002169 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002170 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002171 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002172 }
Fred Quintana60307342009-03-24 22:48:12 -07002173 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002174 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002175 }
2176 }
2177
Carlos Valdivia91979be2015-05-22 14:11:35 -07002178 private void invalidateCustomTokenLocked(
2179 UserAccounts accounts,
2180 String accountType,
2181 String authToken) {
2182 if (authToken == null || accountType == null) {
2183 return;
2184 }
2185 // Also wipe out cached token in memory.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002186 accounts.accountTokenCaches.remove(accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002187 }
2188
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002189 private void invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
2190 String authToken) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002191 if (authToken == null || accountType == null) {
2192 return;
2193 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002194 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fred Quintana33269202009-04-20 16:05:10 -07002195 try {
2196 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002197 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002198 String accountName = cursor.getString(1);
2199 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002200 accounts.accountsDb.deleteAuthToken(authTokenId);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002201 writeAuthTokenIntoCacheLocked(
2202 accounts,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002203 new Account(accountName, accountType),
2204 authTokenType,
2205 null);
Fred Quintana60307342009-03-24 22:48:12 -07002206 }
Fred Quintana33269202009-04-20 16:05:10 -07002207 } finally {
2208 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002209 }
2210 }
2211
Carlos Valdivia91979be2015-05-22 14:11:35 -07002212 private void saveCachedToken(
2213 UserAccounts accounts,
2214 Account account,
2215 String callerPkg,
2216 byte[] callerSigDigest,
2217 String tokenType,
2218 String token,
2219 long expiryMillis) {
2220
2221 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2222 return;
2223 }
2224 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002225 UserHandle.of(accounts.userId));
Carlos Valdivia91979be2015-05-22 14:11:35 -07002226 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002227 accounts.accountTokenCaches.put(
2228 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002229 }
2230 }
2231
Amith Yamasani04e0d262012-02-14 11:50:53 -08002232 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2233 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002234 if (account == null || type == null) {
2235 return false;
2236 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002237 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002238 UserHandle.of(accounts.userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002239 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002240 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002241 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002242 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002243 if (accountId < 0) {
2244 return false;
2245 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002246 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2247 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2248 accounts.accountsDb.setTransactionSuccessful();
2249 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002250 return true;
2251 }
Fred Quintana33269202009-04-20 16:05:10 -07002252 return false;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002253 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002254 accounts.accountsDb.endTransaction();
Fred Quintana33269202009-04-20 16:05:10 -07002255 }
Fred Quintana60307342009-03-24 22:48:12 -07002256 }
2257 }
2258
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002259 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002260 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002261 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002262 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2263 Log.v(TAG, "peekAuthToken: " + account
2264 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002265 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002266 + ", pid " + Binder.getCallingPid());
2267 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002268 Preconditions.checkNotNull(account, "account cannot be null");
2269 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002270 int userId = UserHandle.getCallingUserId();
2271 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002272 String msg = String.format(
2273 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2274 callingUid,
2275 account.type);
2276 throw new SecurityException(msg);
2277 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002278 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002279 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2280 + callingUid);
2281 return null;
2282 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002283 long identityToken = clearCallingIdentity();
2284 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002285 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002286 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002287 } finally {
2288 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002289 }
Fred Quintana60307342009-03-24 22:48:12 -07002290 }
2291
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002292 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002293 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002294 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002295 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2296 Log.v(TAG, "setAuthToken: " + account
2297 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002298 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002299 + ", pid " + Binder.getCallingPid());
2300 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002301 Preconditions.checkNotNull(account, "account cannot be null");
2302 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002303 int userId = UserHandle.getCallingUserId();
2304 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002305 String msg = String.format(
2306 "uid %s cannot set auth tokens associated with accounts of type: %s",
2307 callingUid,
2308 account.type);
2309 throw new SecurityException(msg);
2310 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002311 long identityToken = clearCallingIdentity();
2312 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002313 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002314 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002315 } finally {
2316 restoreCallingIdentity(identityToken);
2317 }
Fred Quintana60307342009-03-24 22:48:12 -07002318 }
2319
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002320 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002321 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002322 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002323 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2324 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002325 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002326 + ", pid " + Binder.getCallingPid());
2327 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002328 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002329 int userId = UserHandle.getCallingUserId();
2330 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002331 String msg = String.format(
2332 "uid %s cannot set secrets for accounts of type: %s",
2333 callingUid,
2334 account.type);
2335 throw new SecurityException(msg);
2336 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002337 long identityToken = clearCallingIdentity();
2338 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002339 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002340 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002341 } finally {
2342 restoreCallingIdentity(identityToken);
2343 }
Fred Quintana60307342009-03-24 22:48:12 -07002344 }
2345
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002346 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2347 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002348 if (account == null) {
2349 return;
2350 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002351 boolean isChanged = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002352 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002353 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002354 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002355 final long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002356 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002357 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2358 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002359 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002360 accounts.accountTokenCaches.remove(account);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002361 accounts.accountsDb.setTransactionSuccessful();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002362 // If there is an account whose password will be updated and the database
2363 // transactions succeed, then we say that a change has occured. Even if the
2364 // new password is the same as the old and there were no authtokens to delete.
2365 isChanged = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002366 String action = (password == null || password.length() == 0) ?
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002367 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2368 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2369 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
Costin Manolachef5ffe892011-01-19 09:35:32 -08002370 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002371 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002372 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002373 if (isChanged) {
2374 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002375 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002376 sendAccountsChangedBroadcast(accounts.userId);
2377 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002378 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002379 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002380 }
2381
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002382 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002383 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002384 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002385 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2386 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002387 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002388 + ", pid " + Binder.getCallingPid());
2389 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002390 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002391 int userId = UserHandle.getCallingUserId();
2392 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002393 String msg = String.format(
2394 "uid %s cannot clear passwords for accounts of type: %s",
2395 callingUid,
2396 account.type);
2397 throw new SecurityException(msg);
2398 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002399 long identityToken = clearCallingIdentity();
2400 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002401 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002402 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002403 } finally {
2404 restoreCallingIdentity(identityToken);
2405 }
Fred Quintana60307342009-03-24 22:48:12 -07002406 }
2407
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002408 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002409 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002410 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002411 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2412 Log.v(TAG, "setUserData: " + account
2413 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002414 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002415 + ", pid " + Binder.getCallingPid());
2416 }
Fred Quintana382601f2010-03-25 12:25:10 -07002417 if (key == null) throw new IllegalArgumentException("key is null");
2418 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002419 int userId = UserHandle.getCallingUserId();
2420 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002421 String msg = String.format(
2422 "uid %s cannot set user data for accounts of type: %s",
2423 callingUid,
2424 account.type);
2425 throw new SecurityException(msg);
2426 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002427 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002428 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002429 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002430 synchronized (accounts.cacheLock) {
2431 if (!accountExistsCacheLocked(accounts, account)) {
2432 return;
2433 }
2434 setUserdataInternalLocked(accounts, account, key, value);
2435 }
Fred Quintana60307342009-03-24 22:48:12 -07002436 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002437 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002438 }
2439 }
2440
Simranjit Kohli858511c2016-03-10 18:36:11 +00002441 private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
2442 if (accounts.accountCache.containsKey(account.type)) {
2443 for (Account acc : accounts.accountCache.get(account.type)) {
2444 if (acc.name.equals(account.name)) {
2445 return true;
2446 }
2447 }
2448 }
2449 return false;
2450 }
2451
2452 private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002453 String value) {
Fred Quintana31957f12009-10-21 13:43:10 -07002454 if (account == null || key == null) {
2455 return;
2456 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002457 accounts.accountsDb.beginTransaction();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002458 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002459 long accountId = accounts.accountsDb.findDeAccountId(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002460 if (accountId < 0) {
2461 return;
2462 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002463 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002464 if (extrasId < 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002465 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002466 if (extrasId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002467 return;
2468 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002469 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002470 return;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002471 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002472 writeUserDataIntoCacheLocked(accounts, account, key, value);
2473 accounts.accountsDb.setTransactionSuccessful();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002474 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002475 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002476 }
2477 }
2478
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002479 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002480 if (result == null) {
2481 Log.e(TAG, "the result is unexpectedly null", new Exception());
2482 }
2483 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2484 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2485 + response);
2486 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002487 try {
2488 response.onResult(result);
2489 } catch (RemoteException e) {
2490 // if the caller is dead then there is no one to care about remote
2491 // exceptions
2492 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2493 Log.v(TAG, "failure while notifying response", e);
2494 }
2495 }
2496 }
2497
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002498 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002499 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2500 final String authTokenType)
2501 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002502 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2503 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002504
Fred Quintanad9640ec2012-05-23 12:37:00 -07002505 final int callingUid = getCallingUid();
2506 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002507 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002508 throw new SecurityException("can only call from system");
2509 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002510 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002511 long identityToken = clearCallingIdentity();
2512 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002513 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002514 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2515 false /* stripAuthTokenFromResult */, null /* accountName */,
2516 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002517 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002518 protected String toDebugString(long now) {
2519 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002520 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002521 + ", authTokenType " + authTokenType;
2522 }
2523
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002524 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002525 public void run() throws RemoteException {
2526 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2527 }
2528
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002529 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002530 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002531 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002532 if (result != null) {
2533 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2534 Bundle bundle = new Bundle();
2535 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2536 super.onResult(bundle);
2537 return;
2538 } else {
2539 super.onResult(result);
2540 }
2541 }
2542 }.bind();
2543 } finally {
2544 restoreCallingIdentity(identityToken);
2545 }
2546 }
2547
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002548 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002549 public void getAuthToken(
2550 IAccountManagerResponse response,
2551 final Account account,
2552 final String authTokenType,
2553 final boolean notifyOnAuthFailure,
2554 final boolean expectActivityLaunch,
2555 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002556 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002557 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2558 Log.v(TAG, "getAuthToken: " + account
2559 + ", response " + response
2560 + ", authTokenType " + authTokenType
2561 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2562 + ", expectActivityLaunch " + expectActivityLaunch
2563 + ", caller's uid " + Binder.getCallingUid()
2564 + ", pid " + Binder.getCallingPid());
2565 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002566 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002567 try {
2568 if (account == null) {
2569 Slog.w(TAG, "getAuthToken called with null account");
2570 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2571 return;
2572 }
2573 if (authTokenType == null) {
2574 Slog.w(TAG, "getAuthToken called with null authTokenType");
2575 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2576 return;
2577 }
2578 } catch (RemoteException e) {
2579 Slog.w(TAG, "Failed to report error back to the client." + e);
2580 return;
2581 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002582 int userId = UserHandle.getCallingUserId();
2583 long ident = Binder.clearCallingIdentity();
2584 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002585 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002586 try {
2587 accounts = getUserAccounts(userId);
2588 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2589 AuthenticatorDescription.newKey(account.type), accounts.userId);
2590 } finally {
2591 Binder.restoreCallingIdentity(ident);
2592 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002593
Costin Manolachea40c6302010-12-13 14:50:45 -08002594 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002595 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002596
2597 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002598 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002599 final boolean permissionGranted =
2600 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002601
Carlos Valdivia91979be2015-05-22 14:11:35 -07002602 // Get the calling package. We will use it for the purpose of caching.
2603 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002604 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002605 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002606 try {
2607 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2608 } finally {
2609 Binder.restoreCallingIdentity(ident);
2610 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002611 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2612 String msg = String.format(
2613 "Uid %s is attempting to illegally masquerade as package %s!",
2614 callerUid,
2615 callerPkg);
2616 throw new SecurityException(msg);
2617 }
2618
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002619 // let authenticator know the identity of the caller
2620 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2621 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002622
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002623 if (notifyOnAuthFailure) {
2624 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002625 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002626
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002627 long identityToken = clearCallingIdentity();
2628 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002629 // Distill the caller's package signatures into a single digest.
2630 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2631
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002632 // if the caller has permission, do the peek. otherwise go the more expensive
2633 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002634 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002635 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002636 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002637 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002638 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2639 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2640 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002641 onResult(response, result);
2642 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002643 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002644 }
2645
Carlos Valdivia91979be2015-05-22 14:11:35 -07002646 if (customTokens) {
2647 /*
2648 * Look up tokens in the new cache only if the loginOptions don't have parameters
2649 * outside of those expected to be injected by the AccountManager, e.g.
2650 * ANDORID_PACKAGE_NAME.
2651 */
2652 String token = readCachedTokenInternal(
2653 accounts,
2654 account,
2655 authTokenType,
2656 callerPkg,
2657 callerPkgSigDigest);
2658 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002659 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2660 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2661 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002662 Bundle result = new Bundle();
2663 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2664 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2665 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2666 onResult(response, result);
2667 return;
2668 }
2669 }
2670
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002671 new Session(
2672 accounts,
2673 response,
2674 account.type,
2675 expectActivityLaunch,
2676 false /* stripAuthTokenFromResult */,
2677 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002678 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002679 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002680 protected String toDebugString(long now) {
2681 if (loginOptions != null) loginOptions.keySet();
2682 return super.toDebugString(now) + ", getAuthToken"
2683 + ", " + account
2684 + ", authTokenType " + authTokenType
2685 + ", loginOptions " + loginOptions
2686 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2687 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002688
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002689 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002690 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002691 // If the caller doesn't have permission then create and return the
2692 // "grant permission" intent instead of the "getAuthToken" intent.
2693 if (!permissionGranted) {
2694 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2695 } else {
2696 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2697 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002698 }
2699
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002700 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002701 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002702 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002703 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002704 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002705 Intent intent = newGrantCredentialsPermissionIntent(
2706 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002707 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002708 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002709 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002710 authTokenType,
2711 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002712 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002713 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002714 onResult(bundle);
2715 return;
2716 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002717 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002718 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002719 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2720 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002721 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002722 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002723 "the type and name should not be empty");
2724 return;
2725 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002726 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002727 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002728 saveAuthTokenToDatabase(
2729 mAccounts,
2730 resultAccount,
2731 authTokenType,
2732 authToken);
2733 }
2734 long expiryMillis = result.getLong(
2735 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2736 if (customTokens
2737 && expiryMillis > System.currentTimeMillis()) {
2738 saveCachedToken(
2739 mAccounts,
2740 account,
2741 callerPkg,
2742 callerPkgSigDigest,
2743 authTokenType,
2744 authToken,
2745 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002746 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002747 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002748
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002749 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002750 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002751 /*
2752 * Make sure that the supplied intent is owned by the authenticator
2753 * giving it to the system. Otherwise a malicious authenticator could
2754 * have users launching arbitrary activities by tricking users to
2755 * interact with malicious notifications.
2756 */
2757 checkKeyIntent(
2758 Binder.getCallingUid(),
2759 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002760 doNotification(
2761 mAccounts,
2762 account,
2763 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002764 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002765 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002766 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002767 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002768 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002769 }.bind();
2770 } finally {
2771 restoreCallingIdentity(identityToken);
2772 }
Fred Quintana60307342009-03-24 22:48:12 -07002773 }
2774
Carlos Valdivia91979be2015-05-22 14:11:35 -07002775 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2776 MessageDigest digester;
2777 try {
2778 digester = MessageDigest.getInstance("SHA-256");
2779 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2780 callerPkg, PackageManager.GET_SIGNATURES);
2781 for (Signature sig : pkgInfo.signatures) {
2782 digester.update(sig.toByteArray());
2783 }
2784 } catch (NoSuchAlgorithmException x) {
2785 Log.wtf(TAG, "SHA-256 should be available", x);
2786 digester = null;
2787 } catch (NameNotFoundException e) {
2788 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2789 digester = null;
2790 }
2791 return (digester == null) ? null : digester.digest();
2792 }
2793
Dianne Hackborn41203752012-08-31 14:05:51 -07002794 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002795 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002796 int uid = intent.getIntExtra(
2797 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2798 String authTokenType = intent.getStringExtra(
2799 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002800 final String titleAndSubtitle =
2801 mContext.getString(R.string.permission_request_notification_with_subtitle,
2802 account.name);
2803 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002804 String title = titleAndSubtitle;
2805 String subtitle = "";
2806 if (index > 0) {
2807 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002808 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002809 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002810 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002811 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05002812 Notification n =
2813 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
2814 .setSmallIcon(android.R.drawable.stat_sys_warning)
2815 .setWhen(0)
2816 .setColor(contextForUser.getColor(
2817 com.android.internal.R.color.system_notification_accent_color))
2818 .setContentTitle(title)
2819 .setContentText(subtitle)
2820 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2821 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2822 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002823 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002824 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002825 }
2826
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002827 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2828 int uid, AccountAuthenticatorResponse response, String authTokenType,
2829 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002830
2831 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002832
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002833 if (startInNewTask) {
2834 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2835 // Since it was set in Eclair+ we can't change it without breaking apps using
2836 // the intent from a non-Activity context. This is the default behavior.
2837 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2838 }
2839 intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
2840 authTokenType, uid) + (packageName != null ? packageName : "")));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002841 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002842 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2843 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002844 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002845
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002846 return intent;
2847 }
2848
2849 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2850 int uid) {
2851 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002852 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002853 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002854 final Pair<Pair<Account, String>, Integer> key =
2855 new Pair<Pair<Account, String>, Integer>(
2856 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002857 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002858 if (id == null) {
2859 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002860 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002861 }
2862 }
2863 return id;
2864 }
2865
Amith Yamasani04e0d262012-02-14 11:50:53 -08002866 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002867 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002868 synchronized (accounts.signinRequiredNotificationIds) {
2869 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002870 if (id == null) {
2871 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002872 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002873 }
2874 }
2875 return id;
2876 }
2877
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002878 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002879 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002880 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002881 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002882 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002883 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2884 Log.v(TAG, "addAccount: accountType " + accountType
2885 + ", response " + response
2886 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002887 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002888 + ", expectActivityLaunch " + expectActivityLaunch
2889 + ", caller's uid " + Binder.getCallingUid()
2890 + ", pid " + Binder.getCallingPid());
2891 }
Fred Quintana382601f2010-03-25 12:25:10 -07002892 if (response == null) throw new IllegalArgumentException("response is null");
2893 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002894
Amith Yamasani71e6c692013-03-24 17:39:28 -07002895 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002896 final int uid = Binder.getCallingUid();
2897 final int userId = UserHandle.getUserId(uid);
2898 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002899 try {
2900 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2901 "User is not allowed to add an account!");
2902 } catch (RemoteException re) {
2903 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002904 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002905 return;
2906 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002907 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002908 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002909 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2910 "User cannot modify accounts of this type (policy).");
2911 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002912 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002913 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2914 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002915 return;
2916 }
2917
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002918 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002919 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2920 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2921 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2922
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002923 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002924 long identityToken = clearCallingIdentity();
2925 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002926 UserAccounts accounts = getUserAccounts(usrId);
2927 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002928 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2929 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002930 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002931 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002932 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002933 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002934 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07002935 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07002936 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002937 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002938
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002939 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002940 protected String toDebugString(long now) {
2941 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07002942 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002943 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002944 }
2945 }.bind();
2946 } finally {
2947 restoreCallingIdentity(identityToken);
2948 }
Fred Quintana60307342009-03-24 22:48:12 -07002949 }
2950
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002951 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002952 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
2953 final String authTokenType, final String[] requiredFeatures,
2954 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002955 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002956 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002957 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2958 Log.v(TAG, "addAccount: accountType " + accountType
2959 + ", response " + response
2960 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002961 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002962 + ", expectActivityLaunch " + expectActivityLaunch
2963 + ", caller's uid " + Binder.getCallingUid()
2964 + ", pid " + Binder.getCallingPid()
2965 + ", for user id " + userId);
2966 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002967 Preconditions.checkArgument(response != null, "response cannot be null");
2968 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002969 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002970 if (isCrossUser(callingUid, userId)) {
2971 throw new SecurityException(
2972 String.format(
2973 "User %s trying to add account for %s" ,
2974 UserHandle.getCallingUserId(),
2975 userId));
2976 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002977
2978 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002979 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002980 try {
2981 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2982 "User is not allowed to add an account!");
2983 } catch (RemoteException re) {
2984 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002985 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002986 return;
2987 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002988 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002989 try {
2990 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2991 "User cannot modify accounts of this type (policy).");
2992 } catch (RemoteException re) {
2993 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002994 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2995 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002996 return;
2997 }
2998
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002999 final int pid = Binder.getCallingPid();
3000 final int uid = Binder.getCallingUid();
3001 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3002 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3003 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3004
3005 long identityToken = clearCallingIdentity();
3006 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003007 UserAccounts accounts = getUserAccounts(userId);
3008 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003009 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3010 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003011 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003012 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003013 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003014 @Override
3015 public void run() throws RemoteException {
3016 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3017 options);
3018 }
3019
3020 @Override
3021 protected String toDebugString(long now) {
3022 return super.toDebugString(now) + ", addAccount"
3023 + ", accountType " + accountType
3024 + ", requiredFeatures "
3025 + (requiredFeatures != null
3026 ? TextUtils.join(",", requiredFeatures)
3027 : null);
3028 }
3029 }.bind();
3030 } finally {
3031 restoreCallingIdentity(identityToken);
3032 }
3033 }
3034
Sandra Kwan78812282015-11-04 11:19:47 -08003035 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003036 public void startAddAccountSession(
3037 final IAccountManagerResponse response,
3038 final String accountType,
3039 final String authTokenType,
3040 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003041 final boolean expectActivityLaunch,
3042 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003043 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003044 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3045 Log.v(TAG,
3046 "startAddAccountSession: accountType " + accountType
3047 + ", response " + response
3048 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003049 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003050 + ", expectActivityLaunch " + expectActivityLaunch
3051 + ", caller's uid " + Binder.getCallingUid()
3052 + ", pid " + Binder.getCallingPid());
3053 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003054 Preconditions.checkArgument(response != null, "response cannot be null");
3055 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003056
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003057 final int uid = Binder.getCallingUid();
3058 final int userId = UserHandle.getUserId(uid);
3059 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003060 try {
3061 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3062 "User is not allowed to add an account!");
3063 } catch (RemoteException re) {
3064 }
3065 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3066 return;
3067 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003068 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003069 try {
3070 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3071 "User cannot modify accounts of this type (policy).");
3072 } catch (RemoteException re) {
3073 }
3074 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3075 userId);
3076 return;
3077 }
Sandra Kwan78812282015-11-04 11:19:47 -08003078 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003079 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
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003083 // Check to see if the Password should be included to the caller.
3084 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3085 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003086 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003087
Sandra Kwan78812282015-11-04 11:19:47 -08003088 long identityToken = clearCallingIdentity();
3089 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003090 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003091 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3092 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003093 new StartAccountSession(
3094 accounts,
3095 response,
3096 accountType,
3097 expectActivityLaunch,
3098 null /* accountName */,
3099 false /* authDetailsRequired */,
3100 true /* updateLastAuthenticationTime */,
3101 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003102 @Override
3103 public void run() throws RemoteException {
3104 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3105 requiredFeatures, options);
3106 }
3107
3108 @Override
3109 protected String toDebugString(long now) {
3110 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3111 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3112 + accountType + ", requiredFeatures "
3113 + (requiredFeatures != null ? requiredFeaturesStr : null);
3114 }
3115 }.bind();
3116 } finally {
3117 restoreCallingIdentity(identityToken);
3118 }
3119 }
3120
3121 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3122 private abstract class StartAccountSession extends Session {
3123
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003124 private final boolean mIsPasswordForwardingAllowed;
3125
3126 public StartAccountSession(
3127 UserAccounts accounts,
3128 IAccountManagerResponse response,
3129 String accountType,
3130 boolean expectActivityLaunch,
3131 String accountName,
3132 boolean authDetailsRequired,
3133 boolean updateLastAuthenticationTime,
3134 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003135 super(accounts, response, accountType, expectActivityLaunch,
3136 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3137 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003138 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003139 }
3140
3141 @Override
3142 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003143 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003144 mNumResults++;
3145 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003146 if (result != null
3147 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003148 checkKeyIntent(
3149 Binder.getCallingUid(),
3150 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003151 }
Sandra Kwan78812282015-11-04 11:19:47 -08003152 IAccountManagerResponse response;
3153 if (mExpectActivityLaunch && result != null
3154 && result.containsKey(AccountManager.KEY_INTENT)) {
3155 response = mResponse;
3156 } else {
3157 response = getResponseAndClose();
3158 }
3159 if (response == null) {
3160 return;
3161 }
3162 if (result == null) {
3163 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3164 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3165 + response);
3166 }
3167 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3168 "null bundle returned");
3169 return;
3170 }
3171
3172 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3173 // All AccountManager error codes are greater
3174 // than 0
3175 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3176 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3177 return;
3178 }
3179
Hongming Jin368aa192016-07-29 14:29:54 -07003180 // Omit passwords if the caller isn't permitted to see them.
3181 if (!mIsPasswordForwardingAllowed) {
3182 result.remove(AccountManager.KEY_PASSWORD);
3183 }
3184
Sandra Kwan78812282015-11-04 11:19:47 -08003185 // Strip auth token from result.
3186 result.remove(AccountManager.KEY_AUTHTOKEN);
3187
3188 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3189 Log.v(TAG,
3190 getClass().getSimpleName() + " calling onResult() on response " + response);
3191 }
3192
3193 // Get the session bundle created by authenticator. The
3194 // bundle contains data necessary for finishing the session
3195 // later. The session bundle will be encrypted here and
3196 // decrypted later when trying to finish the session.
3197 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3198 if (sessionBundle != null) {
3199 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3200 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003201 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003202 Log.w(TAG, "Account type in session bundle doesn't match request.");
3203 }
3204 // Add accountType info to session bundle. This will
3205 // override any value set by authenticator.
3206 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3207
3208 // Encrypt session bundle before returning to caller.
3209 try {
3210 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3211 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3212 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3213 } catch (GeneralSecurityException e) {
3214 if (Log.isLoggable(TAG, Log.DEBUG)) {
3215 Log.v(TAG, "Failed to encrypt session bundle!", e);
3216 }
3217 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3218 "failed to encrypt session bundle");
3219 return;
3220 }
3221 }
3222
3223 sendResponse(response, result);
3224 }
3225 }
3226
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003227 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003228 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003229 @NonNull Bundle sessionBundle,
3230 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003231 Bundle appInfo,
3232 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003233 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003234 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003235 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3236 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003237 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003238 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003239 + ", caller's uid " + callingUid
3240 + ", caller's user id " + UserHandle.getCallingUserId()
3241 + ", pid " + Binder.getCallingPid()
3242 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003243 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003244 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003245 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3246 // Account type is added to it before encryption.
3247 if (sessionBundle == null || sessionBundle.size() == 0) {
3248 throw new IllegalArgumentException("sessionBundle is empty");
3249 }
3250
Dmitry Dementyev52745472016-12-02 10:27:45 -08003251 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003252 if (isCrossUser(callingUid, userId)) {
3253 throw new SecurityException(
3254 String.format(
3255 "User %s trying to finish session for %s without cross user permission",
3256 UserHandle.getCallingUserId(),
3257 userId));
3258 }
3259
Sandra Kwan0b84b452016-01-20 15:25:42 -08003260 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003261 sendErrorResponse(response,
3262 AccountManager.ERROR_CODE_USER_RESTRICTED,
3263 "User is not allowed to add an account!");
3264 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3265 return;
3266 }
3267
3268 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003269 final Bundle decryptedBundle;
3270 final String accountType;
3271 // First decrypt session bundle to get account type for checking permission.
3272 try {
3273 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3274 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3275 if (decryptedBundle == null) {
3276 sendErrorResponse(
3277 response,
3278 AccountManager.ERROR_CODE_BAD_REQUEST,
3279 "failed to decrypt session bundle");
3280 return;
3281 }
3282 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3283 // Account type cannot be null. This should not happen if session bundle was created
3284 // properly by #StartAccountSession.
3285 if (TextUtils.isEmpty(accountType)) {
3286 sendErrorResponse(
3287 response,
3288 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3289 "accountType is empty");
3290 return;
3291 }
3292
3293 // If by any chances, decryptedBundle contains colliding keys with
3294 // system info
3295 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3296 // update credentials flow, we should replace with the new values of the current call.
3297 if (appInfo != null) {
3298 decryptedBundle.putAll(appInfo);
3299 }
3300
3301 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003302 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003303 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3304 } catch (GeneralSecurityException e) {
3305 if (Log.isLoggable(TAG, Log.DEBUG)) {
3306 Log.v(TAG, "Failed to decrypt session bundle!", e);
3307 }
3308 sendErrorResponse(
3309 response,
3310 AccountManager.ERROR_CODE_BAD_REQUEST,
3311 "failed to decrypt session bundle");
3312 return;
3313 }
3314
Sandra Kwan0b84b452016-01-20 15:25:42 -08003315 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003316 sendErrorResponse(
3317 response,
3318 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3319 "User cannot modify accounts of this type (policy).");
3320 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3321 userId);
3322 return;
3323 }
3324
3325 long identityToken = clearCallingIdentity();
3326 try {
3327 UserAccounts accounts = getUserAccounts(userId);
3328 logRecordWithUid(
3329 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003330 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3331 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003332 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003333 new Session(
3334 accounts,
3335 response,
3336 accountType,
3337 expectActivityLaunch,
3338 true /* stripAuthTokenFromResult */,
3339 null /* accountName */,
3340 false /* authDetailsRequired */,
3341 true /* updateLastAuthenticationTime */) {
3342 @Override
3343 public void run() throws RemoteException {
3344 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3345 }
3346
3347 @Override
3348 protected String toDebugString(long now) {
3349 return super.toDebugString(now)
3350 + ", finishSession"
3351 + ", accountType " + accountType;
3352 }
3353 }.bind();
3354 } finally {
3355 restoreCallingIdentity(identityToken);
3356 }
3357 }
3358
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003359 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003360 final DevicePolicyManagerInternal dpmi =
3361 LocalServices.getService(DevicePolicyManagerInternal.class);
3362 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003363 if (dpmi == null) {
3364 intent = getDefaultCantAddAccountIntent(errorCode);
3365 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003366 intent = dpmi.createUserRestrictionSupportIntent(userId,
3367 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3368 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3369 intent = dpmi.createShowAdminSupportIntent(userId, false);
3370 }
3371 if (intent == null) {
3372 intent = getDefaultCantAddAccountIntent(errorCode);
3373 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003374 long identityToken = clearCallingIdentity();
3375 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003376 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003377 } finally {
3378 restoreCallingIdentity(identityToken);
3379 }
3380 }
3381
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003382 /**
3383 * Called when we don't know precisely who is preventing us from adding an account.
3384 */
3385 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3386 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3387 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3388 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3389 return cantAddAccount;
3390 }
3391
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003392 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003393 public void confirmCredentialsAsUser(
3394 IAccountManagerResponse response,
3395 final Account account,
3396 final Bundle options,
3397 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003398 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003399 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003400 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003401 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3402 Log.v(TAG, "confirmCredentials: " + account
3403 + ", response " + response
3404 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003405 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003406 + ", pid " + Binder.getCallingPid());
3407 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003408 // Only allow the system process to read accounts of other users
3409 if (isCrossUser(callingUid, userId)) {
3410 throw new SecurityException(
3411 String.format(
3412 "User %s trying to confirm account credentials for %s" ,
3413 UserHandle.getCallingUserId(),
3414 userId));
3415 }
Fred Quintana382601f2010-03-25 12:25:10 -07003416 if (response == null) throw new IllegalArgumentException("response is null");
3417 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003418 long identityToken = clearCallingIdentity();
3419 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003420 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003421 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003422 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003423 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003424 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003425 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003426 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003427 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003428 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003429 protected String toDebugString(long now) {
3430 return super.toDebugString(now) + ", confirmCredentials"
3431 + ", " + account;
3432 }
3433 }.bind();
3434 } finally {
3435 restoreCallingIdentity(identityToken);
3436 }
Fred Quintana60307342009-03-24 22:48:12 -07003437 }
3438
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003439 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003440 public void updateCredentials(IAccountManagerResponse response, final Account account,
3441 final String authTokenType, final boolean expectActivityLaunch,
3442 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003443 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003444 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3445 Log.v(TAG, "updateCredentials: " + account
3446 + ", response " + response
3447 + ", authTokenType " + authTokenType
3448 + ", expectActivityLaunch " + expectActivityLaunch
3449 + ", caller's uid " + Binder.getCallingUid()
3450 + ", pid " + Binder.getCallingPid());
3451 }
Fred Quintana382601f2010-03-25 12:25:10 -07003452 if (response == null) throw new IllegalArgumentException("response is null");
3453 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003454 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003455 long identityToken = clearCallingIdentity();
3456 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003457 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003458 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003459 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003460 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003461 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003462 public void run() throws RemoteException {
3463 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3464 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003465 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003466 protected String toDebugString(long now) {
3467 if (loginOptions != null) loginOptions.keySet();
3468 return super.toDebugString(now) + ", updateCredentials"
3469 + ", " + account
3470 + ", authTokenType " + authTokenType
3471 + ", loginOptions " + loginOptions;
3472 }
3473 }.bind();
3474 } finally {
3475 restoreCallingIdentity(identityToken);
3476 }
Fred Quintana60307342009-03-24 22:48:12 -07003477 }
3478
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003479 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003480 public void startUpdateCredentialsSession(
3481 IAccountManagerResponse response,
3482 final Account account,
3483 final String authTokenType,
3484 final boolean expectActivityLaunch,
3485 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003486 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003487 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3488 Log.v(TAG,
3489 "startUpdateCredentialsSession: " + account + ", response " + response
3490 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3491 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3492 + ", pid " + Binder.getCallingPid());
3493 }
3494 if (response == null) {
3495 throw new IllegalArgumentException("response is null");
3496 }
3497 if (account == null) {
3498 throw new IllegalArgumentException("account is null");
3499 }
Sandra Kwana578d112015-12-16 16:01:43 -08003500
3501 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003502 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003503
3504 // Check to see if the Password should be included to the caller.
3505 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3506 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003507 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003508
Sandra Kwane68c37e2015-11-12 17:11:49 -08003509 long identityToken = clearCallingIdentity();
3510 try {
3511 UserAccounts accounts = getUserAccounts(userId);
3512 new StartAccountSession(
3513 accounts,
3514 response,
3515 account.type,
3516 expectActivityLaunch,
3517 account.name,
3518 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003519 true /* updateLastCredentialTime */,
3520 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003521 @Override
3522 public void run() throws RemoteException {
3523 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3524 loginOptions);
3525 }
3526
3527 @Override
3528 protected String toDebugString(long now) {
3529 if (loginOptions != null)
3530 loginOptions.keySet();
3531 return super.toDebugString(now)
3532 + ", startUpdateCredentialsSession"
3533 + ", " + account
3534 + ", authTokenType " + authTokenType
3535 + ", loginOptions " + loginOptions;
3536 }
3537 }.bind();
3538 } finally {
3539 restoreCallingIdentity(identityToken);
3540 }
3541 }
3542
3543 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003544 public void isCredentialsUpdateSuggested(
3545 IAccountManagerResponse response,
3546 final Account account,
3547 final String statusToken) {
3548 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3549 Log.v(TAG,
3550 "isCredentialsUpdateSuggested: " + account + ", response " + response
3551 + ", caller's uid " + Binder.getCallingUid()
3552 + ", pid " + Binder.getCallingPid());
3553 }
3554 if (response == null) {
3555 throw new IllegalArgumentException("response is null");
3556 }
3557 if (account == null) {
3558 throw new IllegalArgumentException("account is null");
3559 }
3560 if (TextUtils.isEmpty(statusToken)) {
3561 throw new IllegalArgumentException("status token is empty");
3562 }
3563
Sandra Kwan390c9d22016-01-12 14:13:37 -08003564 int usrId = UserHandle.getCallingUserId();
3565 long identityToken = clearCallingIdentity();
3566 try {
3567 UserAccounts accounts = getUserAccounts(usrId);
3568 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3569 false /* stripAuthTokenFromResult */, account.name,
3570 false /* authDetailsRequired */) {
3571 @Override
3572 protected String toDebugString(long now) {
3573 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3574 + ", " + account;
3575 }
3576
3577 @Override
3578 public void run() throws RemoteException {
3579 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3580 }
3581
3582 @Override
3583 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003584 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003585 IAccountManagerResponse response = getResponseAndClose();
3586 if (response == null) {
3587 return;
3588 }
3589
3590 if (result == null) {
3591 sendErrorResponse(
3592 response,
3593 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3594 "null bundle");
3595 return;
3596 }
3597
3598 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3599 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3600 + response);
3601 }
3602 // Check to see if an error occurred. We know if an error occurred because all
3603 // error codes are greater than 0.
3604 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3605 sendErrorResponse(response,
3606 result.getInt(AccountManager.KEY_ERROR_CODE),
3607 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3608 return;
3609 }
3610 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3611 sendErrorResponse(
3612 response,
3613 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3614 "no result in response");
3615 return;
3616 }
3617 final Bundle newResult = new Bundle();
3618 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3619 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3620 sendResponse(response, newResult);
3621 }
3622 }.bind();
3623 } finally {
3624 restoreCallingIdentity(identityToken);
3625 }
3626 }
3627
3628 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003629 public void editProperties(IAccountManagerResponse response, final String accountType,
3630 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003631 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003632 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3633 Log.v(TAG, "editProperties: accountType " + accountType
3634 + ", response " + response
3635 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003636 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003637 + ", pid " + Binder.getCallingPid());
3638 }
Fred Quintana382601f2010-03-25 12:25:10 -07003639 if (response == null) throw new IllegalArgumentException("response is null");
3640 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003641 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003642 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3643 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003644 String msg = String.format(
3645 "uid %s cannot edit authenticator properites for account type: %s",
3646 callingUid,
3647 accountType);
3648 throw new SecurityException(msg);
3649 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003650 long identityToken = clearCallingIdentity();
3651 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003652 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003653 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003654 true /* stripAuthTokenFromResult */, null /* accountName */,
3655 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003656 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003657 public void run() throws RemoteException {
3658 mAuthenticator.editProperties(this, mAccountType);
3659 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003660 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003661 protected String toDebugString(long now) {
3662 return super.toDebugString(now) + ", editProperties"
3663 + ", accountType " + accountType;
3664 }
3665 }.bind();
3666 } finally {
3667 restoreCallingIdentity(identityToken);
3668 }
Fred Quintana60307342009-03-24 22:48:12 -07003669 }
3670
Amith Yamasani12747872015-12-07 14:19:49 -08003671 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003672 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3673 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003674 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003675 throw new SecurityException("Can be called only by system UID");
3676 }
3677 Preconditions.checkNotNull(account, "account cannot be null");
3678 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3679 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3680
3681 final int userId = userHandle.getIdentifier();
3682
3683 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3684
3685 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003686 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003687 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003688 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003689 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003690 return false;
3691 }
3692 }
3693
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003694 // Returns package with oldest target SDK for given UID.
3695 private String getPackageNameForUid(int uid) {
3696 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3697 if (ArrayUtils.isEmpty(packageNames)) {
3698 return null;
3699 }
3700 // For app op checks related to permissions all packages in the UID
3701 // have the same app op state, so doesn't matter which one we pick.
3702 // Update: due to visibility changes we want to use package with oldest target SDK,
3703
3704 String packageName = packageNames[0];
3705 int oldestVersion = Integer.MAX_VALUE;
3706 for (String name : packageNames) {
3707 try {
3708 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3709 if (applicationInfo != null) {
3710 int version = applicationInfo.targetSdkVersion;
3711 if (version < oldestVersion) {
3712 oldestVersion = version;
3713 packageName = name;
3714 }
3715 }
3716 } catch (NameNotFoundException e) {
3717 // skip
3718 }
3719 }
3720 return packageName;
3721 }
3722
Svet Ganovf6d424f12016-09-20 20:18:53 -07003723 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3724 int uid) {
3725 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003726 packageName = getPackageNameForUid(uid);
3727 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003728 return false;
3729 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003730 }
3731
3732 // Use null token which means any token. Having a token means the package
3733 // is trusted by the authenticator, hence it is fine to access the account.
3734 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3735 return true;
3736 }
3737 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003738 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003739
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003740 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003741 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003742 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003743 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003744 }
3745
3746 @Override
3747 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3748 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003749 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003750 throw new SecurityException("Can be called only by system UID");
3751 }
3752
3753 Preconditions.checkNotNull(account, "account cannot be null");
3754 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3755 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3756
3757 final int userId = userHandle.getIdentifier();
3758
3759 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3760
3761 final int uid;
3762 try {
3763 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3764 } catch (NameNotFoundException e) {
3765 Slog.e(TAG, "Unknown package " + packageName);
3766 return null;
3767 }
3768
3769 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3770
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003771 final long identity = Binder.clearCallingIdentity();
3772 try {
3773 return PendingIntent.getActivityAsUser(
3774 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3775 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3776 null, new UserHandle(userId)).getIntentSender();
3777 } finally {
3778 Binder.restoreCallingIdentity(identity);
3779 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003780 }
3781
3782 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3783 int uid, RemoteCallback callback) {
3784 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3785 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3786 @Override
3787 public void onResult(Bundle value) throws RemoteException {
3788 handleAuthenticatorResponse(true);
3789 }
3790
3791 @Override
3792 public void onRequestContinued() {
3793 /* ignore */
3794 }
3795
3796 @Override
3797 public void onError(int errorCode, String errorMessage) throws RemoteException {
3798 handleAuthenticatorResponse(false);
3799 }
3800
3801 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3802 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003803 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003804 UserHandle.getUserHandleForUid(uid));
3805 if (callback != null) {
3806 Bundle result = new Bundle();
3807 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3808 callback.sendResult(result);
3809 }
3810 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003811 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003812 }
3813
3814 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003815 public boolean someUserHasAccount(@NonNull final Account account) {
3816 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3817 throw new SecurityException("Only system can check for accounts across users");
3818 }
3819 final long token = Binder.clearCallingIdentity();
3820 try {
3821 AccountAndUser[] allAccounts = getAllAccounts();
3822 for (int i = allAccounts.length - 1; i >= 0; i--) {
3823 if (allAccounts[i].account.equals(account)) {
3824 return true;
3825 }
3826 }
3827 return false;
3828 } finally {
3829 Binder.restoreCallingIdentity(token);
3830 }
3831 }
3832
Fred Quintana33269202009-04-20 16:05:10 -07003833 private class GetAccountsByTypeAndFeatureSession extends Session {
3834 private final String[] mFeatures;
3835 private volatile Account[] mAccountsOfType = null;
3836 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3837 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003838 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003839 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003840
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003841 public GetAccountsByTypeAndFeatureSession(
3842 UserAccounts accounts,
3843 IAccountManagerResponse response,
3844 String type,
3845 String[] features,
3846 int callingUid,
3847 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003848 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003849 true /* stripAuthTokenFromResult */, null /* accountName */,
3850 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003851 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003852 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003853 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003854 }
3855
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003856 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003857 public void run() throws RemoteException {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003858 synchronized (mAccounts.cacheLock) {
Amith Yamasani27db4682013-03-30 17:07:47 -07003859 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003860 mPackageName, false /* include managed not visible*/);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003861 }
Fred Quintana33269202009-04-20 16:05:10 -07003862 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003863 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003864 mCurrentAccount = 0;
3865
3866 checkAccount();
3867 }
3868
3869 public void checkAccount() {
3870 if (mCurrentAccount >= mAccountsOfType.length) {
3871 sendResult();
3872 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003873 }
Fred Quintana33269202009-04-20 16:05:10 -07003874
Fred Quintana29e94b82010-03-10 12:11:51 -08003875 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3876 if (accountAuthenticator == null) {
3877 // It is possible that the authenticator has died, which is indicated by
3878 // mAuthenticator being set to null. If this happens then just abort.
3879 // There is no need to send back a result or error in this case since
3880 // that already happened when mAuthenticator was cleared.
3881 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3882 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3883 + " connected to the authenticator, " + toDebugString());
3884 }
3885 return;
3886 }
Fred Quintana33269202009-04-20 16:05:10 -07003887 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003888 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003889 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003890 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003891 }
3892 }
3893
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003894 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003895 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003896 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003897 mNumResults++;
3898 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003899 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003900 return;
3901 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003902 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003903 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3904 }
3905 mCurrentAccount++;
3906 checkAccount();
3907 }
3908
3909 public void sendResult() {
3910 IAccountManagerResponse response = getResponseAndClose();
3911 if (response != null) {
3912 try {
3913 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3914 for (int i = 0; i < accounts.length; i++) {
3915 accounts[i] = mAccountsWithFeatures.get(i);
3916 }
Fred Quintana56285a62010-12-02 14:20:51 -08003917 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3918 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3919 + response);
3920 }
Fred Quintana33269202009-04-20 16:05:10 -07003921 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003922 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07003923 response.onResult(result);
3924 } catch (RemoteException e) {
3925 // if the caller is dead then there is no one to care about remote exceptions
3926 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3927 Log.v(TAG, "failure while notifying response", e);
3928 }
3929 }
3930 }
3931 }
3932
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003933 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003934 protected String toDebugString(long now) {
3935 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
3936 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
3937 }
3938 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07003939
Amith Yamasani04e0d262012-02-14 11:50:53 -08003940 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003941 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08003942 * @hide
3943 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003944 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07003945 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003946 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003947 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07003948 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
3949 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003950 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08003951 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003952 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003953 long identityToken = clearCallingIdentity();
3954 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003955 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003956 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003957 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003958 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003959 opPackageName,
3960 visibleAccountTypes,
3961 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003962 } finally {
3963 restoreCallingIdentity(identityToken);
3964 }
3965 }
3966
Amith Yamasanif29f2362012-04-05 18:29:52 -07003967 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003968 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003969 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07003970 * @hide
3971 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003972 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003973 public AccountAndUser[] getRunningAccounts() {
3974 final int[] runningUserIds;
3975 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08003976 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003977 } catch (RemoteException e) {
3978 // Running in system_server; should never happen
3979 throw new RuntimeException(e);
3980 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003981 return getAccounts(runningUserIds);
3982 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07003983
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003984 /**
3985 * Returns accounts for all users, ignores visibility values.
3986 *
3987 * @hide
3988 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003989 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003990 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07003991 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003992 final int[] userIds = new int[users.size()];
3993 for (int i = 0; i < userIds.length; i++) {
3994 userIds[i] = users.get(i).id;
3995 }
3996 return getAccounts(userIds);
3997 }
3998
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003999 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004000 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004001 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004002 for (int userId : userIds) {
4003 UserAccounts userAccounts = getUserAccounts(userId);
4004 if (userAccounts == null) continue;
4005 synchronized (userAccounts.cacheLock) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004006 Account[] accounts = getAccountsFromCacheLocked(
4007 userAccounts,
4008 null /* type */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004009 Binder.getCallingUid(),
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004010 null /* packageName */,
4011 false /* include managed not visible*/);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004012 for (int a = 0; a < accounts.length; a++) {
4013 runningAccounts.add(new AccountAndUser(accounts[a], userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004014 }
4015 }
4016 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004017
4018 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4019 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004020 }
4021
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004022 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004023 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004024 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004025 int callingUid = Binder.getCallingUid();
4026 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004027 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004028 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004029 }
4030
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004031 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004032 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004033 String type,
4034 int userId,
4035 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004036 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004037 String opPackageName,
4038 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004039 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004040 // Only allow the system process to read accounts of other users
4041 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004042 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004043 && mContext.checkCallingOrSelfPermission(
4044 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4045 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004046 throw new SecurityException("User " + UserHandle.getCallingUserId()
4047 + " trying to get account for " + userId);
4048 }
4049
Fred Quintana56285a62010-12-02 14:20:51 -08004050 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4051 Log.v(TAG, "getAccounts: accountType " + type
4052 + ", caller's uid " + Binder.getCallingUid()
4053 + ", pid " + Binder.getCallingPid());
4054 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004055
4056 // If the original calling app was using account choosing activity
4057 // provided by the framework or authenticator we'll passing in
4058 // the original caller's uid here, which is what should be used for filtering.
4059 List<String> managedTypes =
4060 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4061 if (packageUid != -1 &&
4062 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4063 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004064 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004065 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004066 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004067 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4068 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004069 if (visibleAccountTypes.isEmpty()
4070 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004071 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004072 } else if (visibleAccountTypes.contains(type)) {
4073 // Prune the list down to just the requested type.
4074 visibleAccountTypes = new ArrayList<>();
4075 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004076 } // else aggregate all the visible accounts (it won't matter if the
4077 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004078
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004079 long identityToken = clearCallingIdentity();
4080 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004081 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004082 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004083 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004084 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004085 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004086 visibleAccountTypes,
4087 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004088 } finally {
4089 restoreCallingIdentity(identityToken);
4090 }
4091 }
4092
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004093 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004094 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004095 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004096 int callingUid,
4097 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004098 List<String> visibleAccountTypes,
4099 boolean includeUserManagedNotVisible) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004100 synchronized (userAccounts.cacheLock) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004101 ArrayList<Account> visibleAccounts = new ArrayList<>();
4102 for (String visibleType : visibleAccountTypes) {
4103 Account[] accountsForType = getAccountsFromCacheLocked(
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004104 userAccounts, visibleType, callingUid, callingPackage,
4105 includeUserManagedNotVisible);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004106 if (accountsForType != null) {
4107 visibleAccounts.addAll(Arrays.asList(accountsForType));
4108 }
4109 }
4110 Account[] result = new Account[visibleAccounts.size()];
4111 for (int i = 0; i < visibleAccounts.size(); i++) {
4112 result[i] = visibleAccounts.get(i);
4113 }
4114 return result;
4115 }
4116 }
4117
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004118 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004119 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4120 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004121 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004122 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004123 for (Account account : accounts) {
4124 addSharedAccountAsUser(account, userId);
4125 }
4126 }
4127
4128 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004129 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004130 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004131 accounts.accountsDb.deleteSharedAccount(account);
4132 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004133 if (accountId < 0) {
4134 Log.w(TAG, "insertAccountIntoDatabase: " + account
4135 + ", skipping the DB insert failed");
4136 return false;
4137 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004138 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4139 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004140 return true;
4141 }
4142
4143 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004144 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4145 userId = handleIncomingUser(userId);
4146 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004147 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4148 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004149 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004150 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004151 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004152 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004153 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004154 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004155 }
4156 return r > 0;
4157 }
4158
4159 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004160 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004161 return removeSharedAccountAsUser(account, userId, getCallingUid());
4162 }
4163
4164 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004165 userId = handleIncomingUser(userId);
4166 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004167 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4168 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004169 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004170 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004171 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004172 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004173 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004174 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004175 }
4176
4177 @Override
4178 public Account[] getSharedAccountsAsUser(int userId) {
4179 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004180 UserAccounts accounts = getUserAccounts(userId);
4181 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004182 Account[] accountArray = new Account[accountList.size()];
4183 accountList.toArray(accountArray);
4184 return accountArray;
4185 }
4186
4187 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004188 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004189 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004190 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004191 }
4192
Amith Yamasani27db4682013-03-30 17:07:47 -07004193 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004194 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004195 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004196 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004197 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004198 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004199 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4200 + callingUid + " with uid=" + uid);
4201 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004202 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004203 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004204 }
4205
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004206 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004207 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004208 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4209 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004210 int callingUid = Binder.getCallingUid();
4211 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004212 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004213 int packageUid = -1;
4214 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004215 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4216 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004217 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004218 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004219 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004220 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004221 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4222 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004223 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004224 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004225 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004226 }
4227
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004228 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004229 public void getAccountsByFeatures(
4230 IAccountManagerResponse response,
4231 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004232 String[] features,
4233 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004234 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004235 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004236 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4237 Log.v(TAG, "getAccounts: accountType " + type
4238 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004239 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004240 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004241 + ", pid " + Binder.getCallingPid());
4242 }
Fred Quintana382601f2010-03-25 12:25:10 -07004243 if (response == null) throw new IllegalArgumentException("response is null");
4244 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004245 int userId = UserHandle.getCallingUserId();
4246
Svetoslavf3f02ac2015-09-08 14:36:35 -07004247 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4248 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004249 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004250 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004251 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004252 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004253 try {
4254 response.onResult(result);
4255 } catch (RemoteException e) {
4256 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4257 }
4258 return;
4259 }
Fred Quintana33269202009-04-20 16:05:10 -07004260 long identityToken = clearCallingIdentity();
4261 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004262 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004263 if (features == null || features.length == 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004264 Account[] accounts;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004265 synchronized (userAccounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004266 accounts = getAccountsFromCacheLocked(
4267 userAccounts, type, callingUid, opPackageName, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004268 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004269 Bundle result = new Bundle();
4270 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4271 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004272 return;
4273 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004274 new GetAccountsByTypeAndFeatureSession(
4275 userAccounts,
4276 response,
4277 type,
4278 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004279 callingUid,
4280 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004281 } finally {
4282 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004283 }
4284 }
4285
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004286 @Override
4287 public void onAccountAccessed(String token) throws RemoteException {
4288 final int uid = Binder.getCallingUid();
4289 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4290 return;
4291 }
4292 final int userId = UserHandle.getCallingUserId();
4293 final long identity = Binder.clearCallingIdentity();
4294 try {
4295 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4296 if (Objects.equals(account.getAccessId(), token)) {
4297 // An app just accessed the account. At this point it knows about
4298 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004299 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004300 if (!hasAccountAccess(account, null, uid)) {
4301 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4302 uid, true);
4303 }
4304 }
4305 }
4306 } finally {
4307 Binder.restoreCallingIdentity(identity);
4308 }
4309 }
4310
Fred Quintanaa698f422009-04-08 19:14:54 -07004311 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004312 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004313 IAccountManagerResponse mResponse;
4314 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004315 final boolean mExpectActivityLaunch;
4316 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004317 final String mAccountName;
4318 // Indicates if we need to add auth details(like last credential time)
4319 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004320 // If set, we need to update the last authenticated time. This is
4321 // currently
4322 // used on
4323 // successful confirming credentials.
4324 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004325
Fred Quintana33269202009-04-20 16:05:10 -07004326 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004327 private int mNumRequestContinued = 0;
4328 private int mNumErrors = 0;
4329
Fred Quintana60307342009-03-24 22:48:12 -07004330 IAccountAuthenticator mAuthenticator = null;
4331
Fred Quintana8570f742010-02-18 10:32:54 -08004332 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004333 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004334
Amith Yamasani04e0d262012-02-14 11:50:53 -08004335 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004336 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4337 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004338 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4339 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4340 }
4341
4342 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4343 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4344 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004345 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004346 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004347 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004348 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004349 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004350 mResponse = response;
4351 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004352 mExpectActivityLaunch = expectActivityLaunch;
4353 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004354 mAccountName = accountName;
4355 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004356 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004357
Fred Quintanaa698f422009-04-08 19:14:54 -07004358 synchronized (mSessions) {
4359 mSessions.put(toString(), this);
4360 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004361 if (response != null) {
4362 try {
4363 response.asBinder().linkToDeath(this, 0 /* flags */);
4364 } catch (RemoteException e) {
4365 mResponse = null;
4366 binderDied();
4367 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004368 }
Fred Quintana60307342009-03-24 22:48:12 -07004369 }
4370
Fred Quintanaa698f422009-04-08 19:14:54 -07004371 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004372 if (mResponse == null) {
4373 // this session has already been closed
4374 return null;
4375 }
Fred Quintana60307342009-03-24 22:48:12 -07004376 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004377 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004378 return response;
4379 }
4380
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004381 /**
4382 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4383 * security policy.
4384 *
4385 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004386 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004387 * supplied entries in the system Settings app.
4388 */
4389 protected void checkKeyIntent(
4390 int authUid,
4391 Intent intent) throws SecurityException {
4392 long bid = Binder.clearCallingIdentity();
4393 try {
4394 PackageManager pm = mContext.getPackageManager();
4395 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4396 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4397 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004398 if (!isExportedSystemActivity(targetActivityInfo)
4399 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4400 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004401 String pkgName = targetActivityInfo.packageName;
4402 String activityName = targetActivityInfo.name;
4403 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4404 + "does not share a signature with the supplying authenticator (%s).";
4405 throw new SecurityException(
4406 String.format(tmpl, activityName, pkgName, mAccountType));
4407 }
4408 } finally {
4409 Binder.restoreCallingIdentity(bid);
4410 }
4411 }
4412
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004413 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4414 String className = activityInfo.name;
4415 return "android".equals(activityInfo.packageName) &&
4416 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4417 || CantAddAccountActivity.class.getName().equals(className));
4418 }
4419
Fred Quintanaa698f422009-04-08 19:14:54 -07004420 private void close() {
4421 synchronized (mSessions) {
4422 if (mSessions.remove(toString()) == null) {
4423 // the session was already closed, so bail out now
4424 return;
4425 }
4426 }
4427 if (mResponse != null) {
4428 // stop listening for response deaths
4429 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4430
4431 // clear this so that we don't accidentally send any further results
4432 mResponse = null;
4433 }
4434 cancelTimeout();
4435 unbind();
4436 }
4437
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004438 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004439 public void binderDied() {
4440 mResponse = null;
4441 close();
4442 }
4443
4444 protected String toDebugString() {
4445 return toDebugString(SystemClock.elapsedRealtime());
4446 }
4447
4448 protected String toDebugString(long now) {
4449 return "Session: expectLaunch " + mExpectActivityLaunch
4450 + ", connected " + (mAuthenticator != null)
4451 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4452 + "/" + mNumErrors + ")"
4453 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4454 }
4455
Fred Quintana60307342009-03-24 22:48:12 -07004456 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004457 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4458 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4459 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004460 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004461 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004462 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004463 }
4464 }
4465
4466 private void unbind() {
4467 if (mAuthenticator != null) {
4468 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004469 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004470 }
4471 }
4472
Fred Quintana60307342009-03-24 22:48:12 -07004473 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004474 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004475 }
4476
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004477 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004478 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004479 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004480 try {
4481 run();
4482 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004483 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004484 "remote exception");
4485 }
Fred Quintana60307342009-03-24 22:48:12 -07004486 }
4487
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004488 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004489 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004490 mAuthenticator = null;
4491 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004492 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004493 try {
4494 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4495 "disconnected");
4496 } catch (RemoteException e) {
4497 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4498 Log.v(TAG, "Session.onServiceDisconnected: "
4499 + "caught RemoteException while responding", e);
4500 }
4501 }
Fred Quintana60307342009-03-24 22:48:12 -07004502 }
4503 }
4504
Fred Quintanab839afc2009-10-14 15:57:28 -07004505 public abstract void run() throws RemoteException;
4506
Fred Quintana60307342009-03-24 22:48:12 -07004507 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004508 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004509 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004510 try {
4511 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4512 "timeout");
4513 } catch (RemoteException e) {
4514 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4515 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4516 e);
4517 }
4518 }
Fred Quintana60307342009-03-24 22:48:12 -07004519 }
4520 }
4521
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004522 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004523 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004524 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004525 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004526 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004527 if (result != null) {
4528 boolean isSuccessfulConfirmCreds = result.getBoolean(
4529 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004530 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004531 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4532 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004533 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004534 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4535 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004536 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004537 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004538 if (needUpdate || mAuthDetailsRequired) {
4539 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4540 if (needUpdate && accountPresent) {
4541 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4542 }
4543 if (mAuthDetailsRequired) {
4544 long lastAuthenticatedTime = -1;
4545 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004546 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004547 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004548 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004549 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004550 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004551 lastAuthenticatedTime);
4552 }
4553 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004554 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004555 if (result != null
4556 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004557 checkKeyIntent(
4558 Binder.getCallingUid(),
4559 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004560 }
4561 if (result != null
4562 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004563 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4564 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004565 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4566 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004567 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4568 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004569 }
Fred Quintana60307342009-03-24 22:48:12 -07004570 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004571 IAccountManagerResponse response;
4572 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004573 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004574 response = mResponse;
4575 } else {
4576 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004577 }
Fred Quintana60307342009-03-24 22:48:12 -07004578 if (response != null) {
4579 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004580 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004581 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4582 Log.v(TAG, getClass().getSimpleName()
4583 + " calling onError() on response " + response);
4584 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004585 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004586 "null bundle returned");
4587 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004588 if (mStripAuthTokenFromResult) {
4589 result.remove(AccountManager.KEY_AUTHTOKEN);
4590 }
Fred Quintana56285a62010-12-02 14:20:51 -08004591 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4592 Log.v(TAG, getClass().getSimpleName()
4593 + " calling onResult() on response " + response);
4594 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004595 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4596 (intent == null)) {
4597 // All AccountManager error codes are greater than 0
4598 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4599 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4600 } else {
4601 response.onResult(result);
4602 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004603 }
Fred Quintana60307342009-03-24 22:48:12 -07004604 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004605 // if the caller is dead then there is no one to care about remote exceptions
4606 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4607 Log.v(TAG, "failure while notifying response", e);
4608 }
Fred Quintana60307342009-03-24 22:48:12 -07004609 }
4610 }
4611 }
Fred Quintana60307342009-03-24 22:48:12 -07004612
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004613 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004614 public void onRequestContinued() {
4615 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004616 }
4617
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004618 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004619 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004620 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004621 IAccountManagerResponse response = getResponseAndClose();
4622 if (response != null) {
4623 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004624 Log.v(TAG, getClass().getSimpleName()
4625 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004626 }
4627 try {
4628 response.onError(errorCode, errorMessage);
4629 } catch (RemoteException e) {
4630 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4631 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4632 }
4633 }
4634 } else {
4635 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4636 Log.v(TAG, "Session.onError: already closed");
4637 }
Fred Quintana60307342009-03-24 22:48:12 -07004638 }
4639 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004640
4641 /**
4642 * find the component name for the authenticator and initiate a bind
4643 * if no authenticator or the bind fails then return false, otherwise return true
4644 */
4645 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004646 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4647 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4648 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004649 if (authenticatorInfo == null) {
4650 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4651 Log.v(TAG, "there is no authenticator for " + authenticatorType
4652 + ", bailing out");
4653 }
4654 return false;
4655 }
4656
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004657 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004658 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004659 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4660 + " which isn't encryption aware");
4661 return false;
4662 }
4663
Fred Quintanab839afc2009-10-14 15:57:28 -07004664 Intent intent = new Intent();
4665 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4666 intent.setComponent(authenticatorInfo.componentName);
4667 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4668 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4669 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004670 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004671 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004672 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4673 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4674 }
4675 return false;
4676 }
4677
Fred Quintanab839afc2009-10-14 15:57:28 -07004678 return true;
4679 }
Fred Quintana60307342009-03-24 22:48:12 -07004680 }
4681
Svet Ganov5d09c992016-09-07 09:57:41 -07004682 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004683 MessageHandler(Looper looper) {
4684 super(looper);
4685 }
Costin Manolache3348f142009-09-29 18:58:36 -07004686
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004687 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004688 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004689 switch (msg.what) {
4690 case MESSAGE_TIMED_OUT:
4691 Session session = (Session)msg.obj;
4692 session.onTimedOut();
4693 break;
4694
Amith Yamasani5be347b2013-03-31 17:44:31 -07004695 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004696 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004697 break;
4698
Fred Quintana60307342009-03-24 22:48:12 -07004699 default:
4700 throw new IllegalStateException("unhandled message: " + msg.what);
4701 }
4702 }
4703 }
4704
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004705 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004706 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004707 }
4708
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004709 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004710 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004711 }
4712
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004713 /*
4714 * This function receives an opened writable database.
4715 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004716 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004717 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004718 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004719 }
4720
4721 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004722 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004723 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004724 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004725 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004726
4727 class LogRecordTask implements Runnable {
4728 private final String action;
4729 private final String tableName;
4730 private final long accountId;
4731 private final UserAccounts userAccount;
4732 private final int callingUid;
4733 private final long userDebugDbInsertionPoint;
4734
4735 LogRecordTask(final String action,
4736 final String tableName,
4737 final long accountId,
4738 final UserAccounts userAccount,
4739 final int callingUid,
4740 final long userDebugDbInsertionPoint) {
4741 this.action = action;
4742 this.tableName = tableName;
4743 this.accountId = accountId;
4744 this.userAccount = userAccount;
4745 this.callingUid = callingUid;
4746 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4747 }
4748
4749 public void run() {
4750 SQLiteStatement logStatement = userAccount.statementForLogging;
4751 logStatement.bindLong(1, accountId);
4752 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004753 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004754 logStatement.bindLong(4, callingUid);
4755 logStatement.bindString(5, tableName);
4756 logStatement.bindLong(6, userDebugDbInsertionPoint);
4757 logStatement.execute();
4758 logStatement.clearBindings();
4759 }
4760 }
4761
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004762 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4763 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004764 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004765 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004766 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004767 }
4768
4769 /*
4770 * This should only be called once to compile the sql statement for logging
4771 * and to find the insertion point.
4772 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004773 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4774 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4775 .calculateDebugTableInsertionPoint();
4776 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004777 }
4778
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004779 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004780 return asBinder();
4781 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004782
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004783 /**
4784 * Searches array of arguments for the specified string
4785 * @param args array of argument strings
4786 * @param value value to search for
4787 * @return true if the value is contained in the array
4788 */
4789 private static boolean scanArgs(String[] args, String value) {
4790 if (args != null) {
4791 for (String arg : args) {
4792 if (value.equals(arg)) {
4793 return true;
4794 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004795 }
4796 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004797 return false;
4798 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004799
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004800 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004801 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Kenny Root3abd75b2011-09-29 11:00:41 -07004802 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4803 != PackageManager.PERMISSION_GRANTED) {
4804 fout.println("Permission Denial: can't dump AccountsManager from from pid="
4805 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
4806 + " without permission " + android.Manifest.permission.DUMP);
4807 return;
4808 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004809 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004810 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004811
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004812 final List<UserInfo> users = getUserManager().getUsers();
4813 for (UserInfo user : users) {
4814 ipw.println("User " + user + ":");
4815 ipw.increaseIndent();
4816 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4817 ipw.println();
4818 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004819 }
4820 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004821
Amith Yamasani04e0d262012-02-14 11:50:53 -08004822 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4823 String[] args, boolean isCheckinRequest) {
4824 synchronized (userAccounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004825 if (isCheckinRequest) {
4826 // This is a checkin request. *Only* upload the account types and the count of each.
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004827 userAccounts.accountsDb.dumpDeAccountsTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004828 } else {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004829 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004830 Process.SYSTEM_UID, null /* packageName */, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004831 fout.println("Accounts: " + accounts.length);
4832 for (Account account : accounts) {
4833 fout.println(" " + account);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004834 }
Fred Quintana307da1a2010-01-21 14:24:20 -08004835
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004836 // Add debug information.
4837 fout.println();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004838 userAccounts.accountsDb.dumpDebugTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004839 fout.println();
4840 synchronized (mSessions) {
4841 final long now = SystemClock.elapsedRealtime();
4842 fout.println("Active Sessions: " + mSessions.size());
4843 for (Session session : mSessions.values()) {
4844 fout.println(" " + session.toDebugString(now));
4845 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004846 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004847
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004848 fout.println();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004849 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004850 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004851 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004852 }
4853
Amith Yamasani04e0d262012-02-14 11:50:53 -08004854 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004855 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004856 long identityToken = clearCallingIdentity();
4857 try {
4858 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4859 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4860 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004861
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004862 if (intent.getComponent() != null &&
4863 GrantCredentialsPermissionActivity.class.getName().equals(
4864 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004865 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004866 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004867 Context contextForUser = getContextForUser(new UserHandle(userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004868 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07004869 intent.addCategory(String.valueOf(notificationId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004870
Fred Quintana33f889a2009-09-14 17:31:26 -07004871 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004872 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004873 Notification n =
4874 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004875 .setWhen(0)
4876 .setSmallIcon(android.R.drawable.stat_sys_warning)
4877 .setColor(contextForUser.getColor(
4878 com.android.internal.R.color.system_notification_accent_color))
4879 .setContentTitle(String.format(notificationTitleFormat, account.name))
4880 .setContentText(message)
4881 .setContentIntent(PendingIntent.getActivityAsUser(
4882 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004883 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004884 .build();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004885 installNotification(notificationId, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004886 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004887 } finally {
4888 restoreCallingIdentity(identityToken);
4889 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004890 }
4891
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004892 private void installNotification(int notificationId, final Notification notification,
4893 String packageName, int userId) {
4894 final long token = clearCallingIdentity();
4895 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004896 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004897 try {
4898 notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
4899 notificationId, notification, new int[1], userId);
4900 } catch (RemoteException e) {
4901 /* ignore - local call */
4902 }
4903 } finally {
4904 Binder.restoreCallingIdentity(token);
4905 }
Fred Quintana56285a62010-12-02 14:20:51 -08004906 }
4907
Fyodor Kupolovda993802016-09-21 14:47:10 -07004908 private void cancelNotification(int id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004909 cancelNotification(id, mContext.getPackageName(), user);
4910 }
4911
Fyodor Kupolovda993802016-09-21 14:47:10 -07004912 private void cancelNotification(int id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004913 long identityToken = clearCallingIdentity();
4914 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004915 INotificationManager service = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004916 service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
4917 } catch (RemoteException e) {
4918 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004919 } finally {
4920 restoreCallingIdentity(identityToken);
4921 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004922 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004923
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004924 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
4925 final long identity = Binder.clearCallingIdentity();
4926 try {
4927 IPackageManager pm = ActivityThread.getPackageManager();
4928 for (String perm : permissions) {
4929 if (pm.checkPermission(perm, packageName, userId)
4930 == PackageManager.PERMISSION_GRANTED) {
4931 return true;
4932 }
4933 }
4934 } catch (RemoteException e) {
4935 /* ignore - local call */
4936 } finally {
4937 Binder.restoreCallingIdentity(identity);
4938 }
4939 return false;
4940 }
4941
Ian Pedowitz358e51f2016-03-15 17:08:27 +00004942 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
4943 for (String perm : permissions) {
4944 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
4945 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4946 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
4947 }
4948 final int opCode = AppOpsManager.permissionToOpCode(perm);
4949 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
4950 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
4951 return true;
4952 }
4953 }
4954 }
4955 return false;
4956 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004957
Amith Yamasani67df64b2012-12-14 12:09:36 -08004958 private int handleIncomingUser(int userId) {
4959 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004960 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08004961 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
4962 } catch (RemoteException re) {
4963 // Shouldn't happen, local.
4964 }
4965 return userId;
4966 }
4967
Christopher Tateccbf84f2013-05-08 15:25:41 -07004968 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004969 String[] packages;
4970 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004971 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004972 packages = mPackageManager.getPackagesForUid(callingUid);
4973 } finally {
4974 Binder.restoreCallingIdentity(identityToken);
4975 }
4976 if (packages == null) {
4977 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004978 return false;
4979 }
Fred Quintana7be59642009-08-24 18:29:25 -07004980 for (String name : packages) {
4981 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004982 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08004983 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08004984 && (packageInfo.applicationInfo.privateFlags
4985 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07004986 return true;
4987 }
4988 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004989 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07004990 return false;
4991 }
4992 }
4993 return false;
4994 }
4995
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004996 private boolean permissionIsGranted(
4997 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004998 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
4999 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5000 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5001 }
5002 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005003 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005004
5005 if (isPrivileged(callerUid)) {
5006 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5007 Log.v(TAG, "Access to " + account + " granted calling uid "
5008 + callerUid + " privileged");
5009 }
5010 return true;
5011 }
5012 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5013 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5014 Log.v(TAG, "Access to " + account + " granted calling uid "
5015 + callerUid + " manages the account");
5016 }
5017 return true;
5018 }
5019 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5020 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5021 Log.v(TAG, "Access to " + account + " granted calling uid "
5022 + callerUid + " user granted access");
5023 }
5024 return true;
5025 }
5026
5027 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5028 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5029 }
5030
5031 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005032 }
5033
Svetoslavf3f02ac2015-09-08 14:36:35 -07005034 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5035 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005036 if (accountType == null) {
5037 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005038 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005039 return getTypesVisibleToCaller(callingUid, userId,
5040 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005041 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005042 }
5043
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005044 // Method checks visibility for applications targeing API level below {@link
5045 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005046 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005047 private boolean checkGetAccountsPermission(String packageName, int userId) {
5048 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5049 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5050 }
5051
5052 private boolean checkReadContactsPermission(String packageName, int userId) {
5053 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5054 }
5055
5056 /**
5057 * Method checks package uid and signature with Authenticator which manages accountType.
5058 *
5059 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5060 * SIGNATURE_CHECK_MISMATCH otherwise.
5061 */
5062 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5063 if (accountType == null) {
5064 return SIGNATURE_CHECK_MISMATCH;
5065 }
5066
5067 long identityToken = Binder.clearCallingIdentity();
5068 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5069 try {
5070 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5071 } finally {
5072 Binder.restoreCallingIdentity(identityToken);
5073 }
5074 // Check for signature match with Authenticator.
5075 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5076 : serviceInfos) {
5077 if (accountType.equals(serviceInfo.type.type)) {
5078 if (serviceInfo.uid == callingUid) {
5079 return SIGNATURE_CHECK_UID_MATCH;
5080 }
5081 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5082 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5083 return SIGNATURE_CHECK_MATCH;
5084 }
5085 }
5086 }
5087 return SIGNATURE_CHECK_MISMATCH;
5088 }
5089
5090 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005091 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5092 if (accountType == null) {
5093 return false;
5094 } else {
5095 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5096 }
5097 }
5098
Svetoslavf3f02ac2015-09-08 14:36:35 -07005099 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5100 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005101 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005102 }
5103
5104 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005105 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005106 }
5107
5108 private List<String> getTypesForCaller(
5109 int callingUid, int userId, boolean isOtherwisePermitted) {
5110 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005111 long identityToken = Binder.clearCallingIdentity();
5112 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5113 try {
5114 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5115 } finally {
5116 Binder.restoreCallingIdentity(identityToken);
5117 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005118 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005119 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005120 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5121 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005122 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005123 }
5124 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005125 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005126 }
5127
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005128 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5129 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5130 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5131 if (account.name.equals(accountName)) {
5132 return true;
5133 }
5134 }
5135 }
5136 return false;
5137 }
5138
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005139 private static void checkManageUsersPermission(String message) {
5140 if (ActivityManager.checkComponentPermission(
5141 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5142 != PackageManager.PERMISSION_GRANTED) {
5143 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5144 }
5145 }
5146
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005147 private static void checkManageOrCreateUsersPermission(String message) {
5148 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5149 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5150 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5151 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5152 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5153 + message);
5154 }
5155 }
5156
Amith Yamasani04e0d262012-02-14 11:50:53 -08005157 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5158 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005159 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005160 return true;
5161 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005162 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005163 synchronized (accounts.cacheLock) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005164 long grantsCount;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005165 if (authTokenType != null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005166 grantsCount = accounts.accountsDb.findMatchingGrantsCount(callerUid, authTokenType,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005167 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005168 } else {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005169 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005170 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005171 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005172 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005173
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005174 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5175 // TODO: Skip this check when running automated tests. Replace this
5176 // with a more general solution.
5177 Log.d(TAG, "no credentials permission for usage of " + account + ", "
Amith Yamasani04e0d262012-02-14 11:50:53 -08005178 + authTokenType + " by uid " + callerUid
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005179 + " but ignoring since device is in test harness.");
5180 return true;
5181 }
5182 return permissionGranted;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005183 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005184 }
5185
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005186 private boolean isSystemUid(int callingUid) {
5187 String[] packages = null;
5188 long ident = Binder.clearCallingIdentity();
5189 try {
5190 packages = mPackageManager.getPackagesForUid(callingUid);
5191 } finally {
5192 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005193 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005194 if (packages != null) {
5195 for (String name : packages) {
5196 try {
5197 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5198 if (packageInfo != null
5199 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5200 != 0) {
5201 return true;
5202 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005203 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005204 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5205 }
5206 }
5207 } else {
5208 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005209 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005210 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005211 }
5212
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005213 /** Succeeds if any of the specified permissions are granted. */
5214 private void checkReadAccountsPermitted(
5215 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005216 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005217 int userId,
5218 String opPackageName) {
5219 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005220 String msg = String.format(
5221 "caller uid %s cannot access %s accounts",
5222 callingUid,
5223 accountType);
5224 Log.w(TAG, " " + msg);
5225 throw new SecurityException(msg);
5226 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005227 }
5228
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005229 private boolean canUserModifyAccounts(int userId, int callingUid) {
5230 // the managing app can always modify accounts
5231 if (isProfileOwner(callingUid)) {
5232 return true;
5233 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005234 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5235 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5236 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005237 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005238 return true;
5239 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005240
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005241 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5242 // the managing app can always modify accounts
5243 if (isProfileOwner(callingUid)) {
5244 return true;
5245 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005246 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5247 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005248 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005249 if (typesArray == null) {
5250 return true;
5251 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005252 for (String forbiddenType : typesArray) {
5253 if (forbiddenType.equals(accountType)) {
5254 return false;
5255 }
5256 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005257 return true;
5258 }
5259
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005260 private boolean isProfileOwner(int uid) {
5261 final DevicePolicyManagerInternal dpmi =
5262 LocalServices.getService(DevicePolicyManagerInternal.class);
5263 return (dpmi != null)
5264 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5265 }
5266
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005267 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005268 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5269 throws RemoteException {
5270 final int callingUid = getCallingUid();
5271
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005272 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005273 throw new SecurityException();
5274 }
5275
5276 if (value) {
5277 grantAppPermission(account, authTokenType, uid);
5278 } else {
5279 revokeAppPermission(account, authTokenType, uid);
5280 }
5281 }
5282
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005283 /**
5284 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5285 * <p>
5286 * Although this is public it can only be accessed via the AccountManagerService object
5287 * which is in the system. This means we don't need to protect it with permissions.
5288 * @hide
5289 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005290 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005291 if (account == null || authTokenType == null) {
5292 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005293 return;
5294 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005295 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005296 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005297 long accountId = accounts.accountsDb.findDeAccountId(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005298 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005299 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005300 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005301 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005302 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005303
5304 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005305 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005306
5307 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5308 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5309 : mAppPermissionChangeListeners) {
5310 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5311 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005312 }
5313
5314 /**
5315 * Don't allow callers with the given uid permission to get credentials for
5316 * account/authTokenType.
5317 * <p>
5318 * Although this is public it can only be accessed via the AccountManagerService object
5319 * which is in the system. This means we don't need to protect it with permissions.
5320 * @hide
5321 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005322 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005323 if (account == null || authTokenType == null) {
5324 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005325 return;
5326 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005327 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005328 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005329 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005330 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005331 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005332 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005333 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5334 accountId, authTokenType, uid);
5335 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005336 }
5337 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005338 accounts.accountsDb.endTransaction();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005339 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005340
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005341 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
5342 new UserHandle(accounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005343 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005344
5345 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5346 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5347 : mAppPermissionChangeListeners) {
5348 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5349 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005350 }
Fred Quintana56285a62010-12-02 14:20:51 -08005351
Amith Yamasani04e0d262012-02-14 11:50:53 -08005352 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5353 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005354 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005355 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005356 for (Account curAccount : oldAccountsForType) {
5357 if (!curAccount.equals(account)) {
5358 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005359 }
5360 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005361 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005362 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005363 } else {
5364 Account[] newAccountsForType = new Account[newAccountsList.size()];
5365 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005366 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005367 }
Fred Quintana56285a62010-12-02 14:20:51 -08005368 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005369 accounts.userDataCache.remove(account);
5370 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005371 accounts.previousNameCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005372 }
5373
5374 /**
5375 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005376 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5377 * processes and if you will return this account to apps you should return the result.
5378 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005379 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005380 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005381 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005382 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5383 Account[] newAccountsForType = new Account[oldLength + 1];
5384 if (accountsForType != null) {
5385 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005386 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005387 String token = account.getAccessId() != null ? account.getAccessId()
5388 : UUID.randomUUID().toString();
5389 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005390 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005391 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005392 }
5393
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005394 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005395 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
5396 String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005397 String visibilityFilterPackage = callingPackage;
5398 if (visibilityFilterPackage == null) {
5399 visibilityFilterPackage = getPackageNameForUid(callingUid);
5400 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005401 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005402 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005403 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005404 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5405 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5406 || (includeManagedNotVisible
5407 && (visibility
5408 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5409 firstPass.put(account, visibility);
5410 }
5411 }
5412 Map<Account, Integer> secondPass =
5413 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5414
5415 Account[] filtered = new Account[secondPass.size()];
5416 filtered = secondPass.keySet().toArray(filtered);
5417 return filtered;
5418 }
5419
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005420 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005421 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005422 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005423 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005424 // first part is to filter shared accounts.
5425 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005426 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005427 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005428 return unfiltered;
5429 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005430 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005431 if (user != null && user.isRestricted()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005432 String[] packages =
5433 mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005434 if (packages == null) {
5435 packages = new String[] {};
5436 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005437 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005438 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005439 // This might be a temporary way to specify a visible list
5440 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005441 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5442 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005443 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005444 return unfiltered;
5445 }
5446 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005447 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005448 if (ArrayUtils.isEmpty(sharedAccounts)) {
5449 return unfiltered;
5450 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005451 String requiredAccountType = "";
5452 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005453 // If there's an explicit callingPackage specified, check if that package
5454 // opted in to see restricted accounts.
5455 if (callingPackage != null) {
5456 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005457 if (pi != null && pi.restrictedAccountType != null) {
5458 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005459 }
5460 } else {
5461 // Otherwise check if the callingUid has a package that has opted in
5462 for (String packageName : packages) {
5463 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5464 if (pi != null && pi.restrictedAccountType != null) {
5465 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005466 break;
5467 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005468 }
5469 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005470 } catch (NameNotFoundException e) {
5471 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005472 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005473 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005474 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5475 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005476 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005477 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005478 } else {
5479 boolean found = false;
5480 for (Account shared : sharedAccounts) {
5481 if (shared.equals(account)) {
5482 found = true;
5483 break;
5484 }
5485 }
5486 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005487 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005488 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005489 }
5490 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005491 return filtered;
5492 } else {
5493 return unfiltered;
5494 }
5495 }
5496
Amith Yamasani27db4682013-03-30 17:07:47 -07005497 /*
5498 * packageName can be null. If not null, it should be used to filter out restricted accounts
5499 * that the package is not allowed to access.
5500 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005501 @NonNull
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005502 protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005503 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005504 if (callingPackage == null) {
5505 callingPackage = getPackageNameForUid(callingUid);
5506 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005507 if (accountType != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005508 final Account[] accounts = userAccounts.accountCache.get(accountType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005509 if (accounts == null) {
5510 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005511 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005512 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5513 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005514 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005515 } else {
5516 int totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005517 for (Account[] accounts : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005518 totalLength += accounts.length;
5519 }
5520 if (totalLength == 0) {
5521 return EMPTY_ACCOUNT_ARRAY;
5522 }
5523 Account[] accounts = new Account[totalLength];
5524 totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005525 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005526 System.arraycopy(accountsOfType, 0, accounts, totalLength,
5527 accountsOfType.length);
5528 totalLength += accountsOfType.length;
5529 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005530 return filterAccounts(userAccounts, accounts, callingUid, callingPackage,
5531 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005532 }
5533 }
5534
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005535 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005536 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005537 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005538 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005539 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005540 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005541 }
5542 if (value == null) {
5543 userDataForAccount.remove(key);
5544 } else {
5545 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005546 }
5547 }
5548
Carlos Valdivia91979be2015-05-22 14:11:35 -07005549 protected String readCachedTokenInternal(
5550 UserAccounts accounts,
5551 Account account,
5552 String tokenType,
5553 String callingPackage,
5554 byte[] pkgSigDigest) {
5555 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005556 return accounts.accountTokenCaches.get(
5557 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07005558 }
5559 }
5560
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005561 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005562 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005563 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005564 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005565 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005566 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005567 }
5568 if (value == null) {
5569 authTokensForAccount.remove(key);
5570 } else {
5571 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005572 }
5573 }
5574
Amith Yamasani04e0d262012-02-14 11:50:53 -08005575 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5576 String authTokenType) {
5577 synchronized (accounts.cacheLock) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005578 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005579 if (authTokensForAccount == null) {
5580 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005581 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005582 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005583 }
5584 return authTokensForAccount.get(authTokenType);
5585 }
5586 }
5587
Simranjit Kohli858511c2016-03-10 18:36:11 +00005588 protected String readUserDataInternalLocked(
5589 UserAccounts accounts, Account account, String key) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005590 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005591 if (userDataForAccount == null) {
5592 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005593 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005594 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005595 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005596 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005597 }
5598
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005599 private Context getContextForUser(UserHandle user) {
5600 try {
5601 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5602 } catch (NameNotFoundException e) {
5603 // Default to mContext, not finding the package system is running as is unlikely.
5604 return mContext;
5605 }
5606 }
Sandra Kwan78812282015-11-04 11:19:47 -08005607
5608 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5609 try {
5610 response.onResult(result);
5611 } catch (RemoteException e) {
5612 // if the caller is dead then there is no one to care about remote
5613 // exceptions
5614 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5615 Log.v(TAG, "failure while notifying response", e);
5616 }
5617 }
5618 }
5619
5620 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5621 String errorMessage) {
5622 try {
5623 response.onError(errorCode, errorMessage);
5624 } catch (RemoteException e) {
5625 // if the caller is dead then there is no one to care about remote
5626 // exceptions
5627 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5628 Log.v(TAG, "failure while notifying response", e);
5629 }
5630 }
5631 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005632
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005633 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005634 private final Object mLock = new Object();
5635
5636 @GuardedBy("mLock")
5637 private AccountManagerBackupHelper mBackupHelper;
5638
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005639 @Override
5640 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5641 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5642 if (account == null) {
5643 Slog.w(TAG, "account cannot be null");
5644 return;
5645 }
5646 if (packageName == null) {
5647 Slog.w(TAG, "packageName cannot be null");
5648 return;
5649 }
5650 if (userId < UserHandle.USER_SYSTEM) {
5651 Slog.w(TAG, "user id must be concrete");
5652 return;
5653 }
5654 if (callback == null) {
5655 Slog.w(TAG, "callback cannot be null");
5656 return;
5657 }
5658
Svet Ganovf6d424f12016-09-20 20:18:53 -07005659 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5660 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005661 Bundle result = new Bundle();
5662 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5663 callback.sendResult(result);
5664 return;
5665 }
5666
5667 final int uid;
5668 try {
5669 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5670 } catch (NameNotFoundException e) {
5671 Slog.e(TAG, "Unknown package " + packageName);
5672 return;
5673 }
5674
5675 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005676 final UserAccounts userAccounts;
5677 synchronized (mUsers) {
5678 userAccounts = mUsers.get(userId);
5679 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04005680 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005681 doNotification(userAccounts, account, null, intent, packageName, userId);
5682 }
5683
5684 @Override
5685 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5686 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5687 mAppPermissionChangeListeners.add(listener);
5688 }
5689
5690 @Override
5691 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5692 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005693 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005694
5695 @Override
5696 public byte[] backupAccountAccessPermissions(int userId) {
5697 synchronized (mLock) {
5698 if (mBackupHelper == null) {
5699 mBackupHelper = new AccountManagerBackupHelper(
5700 AccountManagerService.this, this);
5701 }
5702 return mBackupHelper.backupAccountAccessPermissions(userId);
5703 }
5704 }
5705
5706 @Override
5707 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5708 synchronized (mLock) {
5709 if (mBackupHelper == null) {
5710 mBackupHelper = new AccountManagerBackupHelper(
5711 AccountManagerService.this, this);
5712 }
5713 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5714 }
5715 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005716 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005717
5718 @VisibleForTesting
5719 static class Injector {
5720 private final Context mContext;
5721
5722 public Injector(Context context) {
5723 mContext = context;
5724 }
5725
5726 Looper getMessageHandlerLooper() {
5727 ServiceThread serviceThread = new ServiceThread(TAG,
5728 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5729 serviceThread.start();
5730 return serviceThread.getLooper();
5731 }
5732
5733 Context getContext() {
5734 return mContext;
5735 }
5736
5737 void addLocalService(AccountManagerInternal service) {
5738 LocalServices.addService(AccountManagerInternal.class, service);
5739 }
5740
5741 String getDeDatabaseName(int userId) {
5742 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5743 AccountsDb.DE_DATABASE_NAME);
5744 return databaseFile.getPath();
5745 }
5746
5747 String getCeDatabaseName(int userId) {
5748 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5749 AccountsDb.CE_DATABASE_NAME);
5750 return databaseFile.getPath();
5751 }
5752
5753 String getPreNDatabaseName(int userId) {
5754 File systemDir = Environment.getDataSystemDirectory();
5755 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5756 PRE_N_DATABASE_NAME);
5757 if (userId == 0) {
5758 // Migrate old file, if it exists, to the new location.
5759 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005760 // accidentally created in the old location,
5761 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005762 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5763 if (oldFile.exists() && !databaseFile.exists()) {
5764 // Check for use directory; create if it doesn't exist, else renameTo will fail
5765 File userDir = Environment.getUserSystemDirectory(userId);
5766 if (!userDir.exists()) {
5767 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005768 throw new IllegalStateException(
5769 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005770 }
5771 }
5772 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005773 throw new IllegalStateException(
5774 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005775 }
5776 }
5777 }
5778 return databaseFile.getPath();
5779 }
5780
5781 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5782 return new AccountAuthenticatorCache(mContext);
5783 }
5784
5785 INotificationManager getNotificationManager() {
5786 return NotificationManager.getService();
5787 }
5788 }
Fred Quintana60307342009-03-24 22:48:12 -07005789}