blob: 77a02b4d2e9dd30baa6c59ff20b28446e2c2e622 [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} */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700205 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800206 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700207 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800208 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700209 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700210 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700211 private final TokenCache accountTokenCaches = new TokenCache();
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700212 /** protected by the {@link #cacheLock} */
213 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700214
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700215 /** protected by the {@link #mReceiversForType},
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700216 * type -> (packageName -> number of active receivers)
217 * type == null is used to get notifications about all account types
218 */
219 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800220
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700221 /**
222 * protected by the {@link #cacheLock}
223 *
224 * Caches the previous names associated with an account. Previous names
225 * should be cached because we expect that when an Account is renamed,
226 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
227 * want to know if the accounts they care about have been renamed.
228 *
229 * The previous names are wrapped in an {@link AtomicReference} so that
230 * we can distinguish between those accounts with no previous names and
231 * those whose previous names haven't been cached (yet).
232 */
233 private final HashMap<Account, AtomicReference<String>> previousNameCache =
234 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800235
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700236 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700237 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700238
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700239 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800240 this.userId = userId;
241 synchronized (cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700242 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800243 }
244 }
245 }
246
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700247 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600248 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700249 // Not thread-safe. Only use in synchronized context
250 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700251 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
252 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800253
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700254 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700255 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700256
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700257 /**
258 * This should only be called by system code. One should only call this after the service
259 * has started.
260 * @return a reference to the AccountManagerService instance
261 * @hide
262 */
263 public static AccountManagerService getSingleton() {
264 return sThis.get();
265 }
Fred Quintana60307342009-03-24 22:48:12 -0700266
Fyodor Kupolovda993802016-09-21 14:47:10 -0700267 public AccountManagerService(Injector injector) {
268 mInjector = injector;
269 mContext = injector.getContext();
270 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700271 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700272 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
273 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800274 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700275
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700276 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800277
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800278 IntentFilter intentFilter = new IntentFilter();
279 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
280 intentFilter.addDataScheme("package");
281 mContext.registerReceiver(new BroadcastReceiver() {
282 @Override
283 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700284 // Don't delete accounts when updating a authenticator's
285 // package.
286 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700287 /* Purging data requires file io, don't block the main thread. This is probably
288 * less than ideal because we are introducing a race condition where old grants
289 * could be exercised until they are purged. But that race condition existed
290 * anyway with the broadcast receiver.
291 *
292 * Ideally, we would completely clear the cache, purge data from the database,
293 * and then rebuild the cache. All under the cache lock. But that change is too
294 * large at this point.
295 */
Dmitry Dementyev0b676422017-03-09 11:51:26 -0800296 final String removedPackageName = intent.getData().getSchemeSpecificPart();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700297 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700298 @Override
299 public void run() {
300 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800301 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800302 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700303 }
304 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700305 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700306 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800307 }
308 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800309
Fyodor Kupolovda993802016-09-21 14:47:10 -0700310 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700311
312 // Need to cancel account request notifications if the update/install can access the account
313 new PackageMonitor() {
314 @Override
315 public void onPackageAdded(String packageName, int uid) {
316 // Called on a handler, and running as the system
317 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
318 }
319
320 @Override
321 public void onPackageUpdateFinished(String packageName, int uid) {
322 // Called on a handler, and running as the system
323 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
324 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700325 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700326
327 // Cancel account request notification if an app op was preventing the account access
328 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
329 new AppOpsManager.OnOpChangedInternalListener() {
330 @Override
331 public void onOpChanged(int op, String packageName) {
332 try {
333 final int userId = ActivityManager.getCurrentUser();
334 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
335 final int mode = mAppOpsManager.checkOpNoThrow(
336 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
337 if (mode == AppOpsManager.MODE_ALLOWED) {
338 final long identity = Binder.clearCallingIdentity();
339 try {
340 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
341 } finally {
342 Binder.restoreCallingIdentity(identity);
343 }
344 }
345 } catch (NameNotFoundException e) {
346 /* ignore */
347 }
348 }
349 });
350
351 // Cancel account request notification if a permission was preventing the account access
352 mPackageManager.addOnPermissionsChangeListener(
353 (int uid) -> {
354 Account[] accounts = null;
355 String[] packageNames = mPackageManager.getPackagesForUid(uid);
356 if (packageNames != null) {
357 final int userId = UserHandle.getUserId(uid);
358 final long identity = Binder.clearCallingIdentity();
359 try {
360 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800361 // if app asked for permission we need to cancel notification even
362 // for O+ applications.
363 if (mPackageManager.checkPermission(
364 Manifest.permission.GET_ACCOUNTS,
365 packageName) != PackageManager.PERMISSION_GRANTED) {
366 continue;
367 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700368
369 if (accounts == null) {
370 accounts = getAccountsAsUser(null, userId, "android");
371 if (ArrayUtils.isEmpty(accounts)) {
372 return;
373 }
374 }
375
376 for (Account account : accounts) {
377 cancelAccountAccessRequestNotificationIfNeeded(
378 account, uid, packageName, true);
379 }
380 }
381 } finally {
382 Binder.restoreCallingIdentity(identity);
383 }
384 }
385 });
386 }
387
388 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
389 boolean checkAccess) {
390 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
391 for (Account account : accounts) {
392 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
393 }
394 }
395
396 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
397 boolean checkAccess) {
398 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
399 for (Account account : accounts) {
400 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
401 }
402 }
403
404 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
405 boolean checkAccess) {
406 String[] packageNames = mPackageManager.getPackagesForUid(uid);
407 if (packageNames != null) {
408 for (String packageName : packageNames) {
409 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
410 packageName, checkAccess);
411 }
412 }
413 }
414
415 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
416 int uid, String packageName, boolean checkAccess) {
417 if (!checkAccess || hasAccountAccess(account, packageName,
418 UserHandle.getUserHandleForUid(uid))) {
419 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700420 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700421 UserHandle.getUserHandleForUid(uid));
422 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800423 }
424
Dianne Hackborn164371f2013-10-01 19:10:13 -0700425 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800426 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800427 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800428 Bundle.setDefusable(extras, true);
429
430 final int callingUid = Binder.getCallingUid();
431 if (Log.isLoggable(TAG, Log.VERBOSE)) {
432 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
433 + ", pid " + Binder.getCallingPid());
434 }
435 Preconditions.checkNotNull(account, "account cannot be null");
436 int userId = UserHandle.getCallingUserId();
437 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
438 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
439 callingUid, account.type);
440 throw new SecurityException(msg);
441 }
442 /*
443 * Child users are not allowed to add accounts. Only the accounts that are shared by the
444 * parent profile can be added to child profile.
445 *
446 * TODO: Only allow accounts that were shared to be added by a limited user.
447 */
448 // fails if the account already exists
449 long identityToken = clearCallingIdentity();
450 try {
451 UserAccounts accounts = getUserAccounts(userId);
452 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800453 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800454 } finally {
455 restoreCallingIdentity(identityToken);
456 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700457 }
458
459 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800460 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
461 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800462 int callingUid = Binder.getCallingUid();
463 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
464 List<String> managedTypes =
465 getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
466
467 if ((accountType != null && !managedTypes.contains(accountType))
468 || (accountType == null && !isSystemUid)) {
469 throw new SecurityException(
470 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
471 + callingUid + " with packageName=" + packageName);
472 }
473 if (accountType != null) {
474 managedTypes = new ArrayList<String>();
475 managedTypes.add(accountType);
476 }
477
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800478 long identityToken = clearCallingIdentity();
479 try {
480 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
481 getUserAccounts(UserHandle.getUserId(callingUid)));
482 } finally {
483 restoreCallingIdentity(identityToken);
484 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800485 }
486
487 /*
488 * accountTypes may not be null
489 */
490 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
491 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
492 int uid = 0;
493 try {
494 uid = mPackageManager.getPackageUidAsUser(packageName,
495 UserHandle.getUserId(callingUid));
496 } catch (NameNotFoundException e) {
497 Log.d(TAG, "Package not found " + e.getMessage());
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800498 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800499 }
500
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800501 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800502 for (String accountType : accountTypes) {
503 synchronized (accounts.cacheLock) {
504 final Account[] accountsOfType = accounts.accountCache.get(accountType);
505 if (accountsOfType != null) {
506 for (Account account : accountsOfType) {
507 result.put(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800508 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800509 }
510 }
511 }
512 }
513 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800514 }
515
516 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800517 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700518 Preconditions.checkNotNull(account, "account cannot be null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700519 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800520 int userId = UserHandle.getUserId(callingUid);
521 UserAccounts accounts = getUserAccounts(userId);
522 if (!isAccountManagedByCaller(account.type, callingUid, userId)
523 && !isSystemUid(callingUid)) {
524 String msg =
525 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700526 throw new SecurityException(msg);
527 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700528 synchronized (accounts.cacheLock) {
529 return getPackagesAndVisibilityForAccountLocked(account, accounts);
530 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800531 }
532
533 /**
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700534 * Returns Map with all package names and visibility values for given account.
535 * The method and returned map must be guarded by accounts.cacheLock
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800536 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800537 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800538 * @param accounts UserAccount that currently hosts the account and application
539 *
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700540 * @return Map with cache for package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800541 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700542 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800543 UserAccounts accounts) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700544 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account);
545 if (accountVisibility == null) {
546 Log.d(TAG, "Visibility was not initialized");
547 accountVisibility = new HashMap<>();
548 accounts.visibilityCache.put(account, accountVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800549 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700550 return accountVisibility;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700551 }
552
553 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700554 public int getAccountVisibility(Account account, String packageName) {
555 Preconditions.checkNotNull(account, "account cannot be null");
556 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800557 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700558 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
559 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800560 && !isSystemUid(callingUid)) {
561 String msg = String.format(
562 "uid %s cannot get secrets for accounts of type: %s",
563 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700564 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800565 throw new SecurityException(msg);
566 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700567 return resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800568 }
569
570 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800571 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800572 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800573 * @param account The account to check visibility.
574 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800575 * @param accounts UserAccount that currently hosts the account and application
576 *
577 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
578 *
579 */
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700580 private int getAccountVisibilityFromCache(Account account, String packageName,
581 UserAccounts accounts) {
582 synchronized (accounts.cacheLock) {
583 Map<String, Integer> accountVisibility =
584 getPackagesAndVisibilityForAccountLocked(account, accounts);
585 Integer visibility = accountVisibility.get(packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800586 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800587 }
588 }
589
590 /**
591 * Method which handles default values for Account visibility.
592 *
593 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800594 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800595 * @param accounts UserAccount that currently hosts the account and application
596 *
597 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
598 *
599 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800600 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800601 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800602 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800603 int uid = -1;
604 try {
605 long identityToken = clearCallingIdentity();
606 try {
607 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
608 } finally {
609 restoreCallingIdentity(identityToken);
610 }
611 } catch (NameNotFoundException e) {
612 Log.d(TAG, "Package not found " + e.getMessage());
613 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800614 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800615
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800616 // System visibility can not be restricted.
617 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
618 return AccountManager.VISIBILITY_VISIBLE;
619 }
620
621 int signatureCheckResult =
622 checkPackageSignature(account.type, uid, accounts.userId);
623
624 // Authenticator can not restrict visibility to itself.
625 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
626 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
627 }
628
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800629 if (isSpecialPackageKey(packageName)) {
630 Log.d(TAG, "Package name is forbidden: " + packageName);
631 return AccountManager.VISIBILITY_NOT_VISIBLE;
632 }
633
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800634 // Return stored value if it was set.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700635 int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800636
637 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
638 return visibility;
639 }
640
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800641 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
642 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
643
644 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800645 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800646 return AccountManager.VISIBILITY_VISIBLE;
647 }
648 // Apps with READ_CONTACTS permission get visibility by default even post O.
649 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
650
651 boolean preO = isPreOApplication(packageName);
652 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
653 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800654 || canReadContacts || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800655 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
656 // match.
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700657 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800658 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800659 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
660 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
661 }
662 } else {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700663 visibility = getAccountVisibilityFromCache(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800664 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800665 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
666 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
667 }
668 }
669 return visibility;
670 }
671
672 /**
673 * Checks targetSdk for a package;
674 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800675 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800676 *
677 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
678 * undefined
679 */
680 private boolean isPreOApplication(String packageName) {
681 try {
682 long identityToken = clearCallingIdentity();
683 ApplicationInfo applicationInfo;
684 try {
685 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
686 } finally {
687 restoreCallingIdentity(identityToken);
688 }
689
690 if (applicationInfo != null) {
691 int version = applicationInfo.targetSdkVersion;
692 return version < android.os.Build.VERSION_CODES.O;
693 }
694 return true;
695 } catch (NameNotFoundException e) {
696 Log.d(TAG, "Package not found " + e.getMessage());
697 return true;
698 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800699 }
700
701 @Override
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700702 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
703 Preconditions.checkNotNull(account, "account cannot be null");
704 Preconditions.checkNotNull(packageName, "packageName cannot be null");
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800705 int callingUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700706 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
707 if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800708 && !isSystemUid(callingUid)) {
709 String msg = String.format(
710 "uid %s cannot get secrets for accounts of type: %s",
711 callingUid,
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700712 account.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800713 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700714 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700715 return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
716 accounts);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700717 }
718
719 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800720 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700721 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800722 * @param account Account to update visibility.
723 * @param packageName Package name for which visibility is updated.
724 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800725 * @param notify if the flag is set applications will get notification about visibility change
726 * @param accounts UserAccount that currently hosts the account and application
727 *
728 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700729 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800730 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800731 boolean notify, UserAccounts accounts) {
732 synchronized (accounts.cacheLock) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700733 Map<String, Integer> packagesToVisibility;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800734 if (notify) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800735 if (isSpecialPackageKey(packageName)) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700736 packagesToVisibility =
737 getRequestingPackages(account, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800738 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800739 if (!packageExistsForUser(packageName, accounts.userId)) {
740 return false; // package is not installed.
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100741 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700742 packagesToVisibility = new HashMap<>();
743 packagesToVisibility.put(packageName,
744 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800745 }
746 } else {
747 // Notifications will not be send.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800748 if (!isSpecialPackageKey(packageName) &&
749 !packageExistsForUser(packageName, accounts.userId)) {
750 // package is not installed and not meta value.
751 return false;
752 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700753 packagesToVisibility = new HashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800754 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800755
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700756 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800757 return false;
758 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800759
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800760 if (notify) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700761 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
762 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
763 notifyPackage(packageToVisibility.getKey(), accounts);
764 }
765 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800766 sendAccountsChangedBroadcast(accounts.userId);
767 }
768 return true;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700769 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700770 }
771
Dmitry Dementyev71fa5262017-03-23 12:29:17 -0700772 // Update account visibility in cache and database.
773 private boolean updateAccountVisibilityLocked(Account account, String packageName,
774 int newVisibility, UserAccounts accounts) {
775 final long accountId = accounts.accountsDb.findDeAccountId(account);
776 if (accountId < 0) {
777 return false;
778 }
779
780 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
781 try {
782 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
783 newVisibility)) {
784 return false;
785 }
786 } finally {
787 StrictMode.setThreadPolicy(oldPolicy);
788 }
789 Map<String, Integer> accountVisibility =
790 getPackagesAndVisibilityForAccountLocked(account, accounts);
791 accountVisibility.put(packageName, newVisibility);
792 return true;
793 }
794
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700795 @Override
796 public void registerAccountListener(String[] accountTypes, String opPackageName) {
797 int callingUid = Binder.getCallingUid();
798 mAppOpsManager.checkPackage(callingUid, opPackageName);
799 registerAccountListener(accountTypes, opPackageName,
800 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800801 }
802
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700803 private void registerAccountListener(String[] accountTypes, String opPackageName,
804 UserAccounts accounts) {
805 synchronized (accounts.mReceiversForType) {
806 if (accountTypes == null) {
807 // null for any type
808 accountTypes = new String[] {null};
809 }
810 for (String type : accountTypes) {
811 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
812 if (receivers == null) {
813 receivers = new HashMap<>();
814 accounts.mReceiversForType.put(type, receivers);
815 }
816 Integer cnt = receivers.get(opPackageName);
817 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800818 }
819 }
820 }
821
Dmitry Dementyev8882d882017-03-14 17:25:46 -0700822 @Override
823 public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
824 int callingUid = Binder.getCallingUid();
825 mAppOpsManager.checkPackage(callingUid, opPackageName);
826 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
827 synchronized (accounts.mReceiversForType) {
828 if (accountTypes == null) {
829 // null for any type
830 accountTypes = new String[] {null};
831 }
832 for (String type : accountTypes) {
833 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
834 if (receivers == null || receivers.get(opPackageName) == null) {
835 throw new IllegalArgumentException("attempt to unregister wrong receiver");
836 }
837 Integer cnt = receivers.get(opPackageName);
838 if (cnt == 1) {
839 receivers.remove(opPackageName);
840 } else {
841 receivers.put(opPackageName, cnt - 1);
842 }
843 }
844 }
845 }
846
847 // Send notification to all packages which can potentially see the account
848 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
849 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
850 // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
851 // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
852 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
853 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
854 notifyPackage(packageToVisibility.getKey(), accounts);
855 }
856 }
857 }
858
859 /**
860 * Sends a direct intent to a package, notifying it of account visibility change.
861 *
862 * @param packageName to send Account to
863 * @param accounts UserAccount that currently hosts the account
864 */
865 private void notifyPackage(String packageName, UserAccounts accounts) {
866 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
867 intent.setPackage(packageName);
868 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
869 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
870 }
871
872 // Returns a map from package name to visibility, for packages subscribed
873 // to notifications about any account type, or type of provided account
874 // account type or all types.
875 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
876 Set<String> packages = new HashSet<>();
877 synchronized (accounts.mReceiversForType) {
878 for (String type : new String[] {account.type, null}) {
879 Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
880 if (receivers != null) {
881 packages.addAll(receivers.keySet());
882 }
883 }
884 }
885 Map<String, Integer> result = new HashMap<>();
886 for (String packageName : packages) {
887 result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
888 }
889 return result;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800890 }
891
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800892 private boolean packageExistsForUser(String packageName, int userId) {
893 try {
894 long identityToken = clearCallingIdentity();
895 try {
896 mPackageManager.getPackageUidAsUser(packageName, userId);
897 return true; // package exist
898 } finally {
899 restoreCallingIdentity(identityToken);
900 }
901 } catch (NameNotFoundException e) {
902 return false;
903 }
904 }
905
906 /**
907 * Returns true if packageName is one of special values.
908 */
909 private boolean isSpecialPackageKey(String packageName) {
910 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
911 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
912 }
913
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800914 private void sendAccountsChangedBroadcast(int userId) {
915 Log.i(TAG, "the accounts changed, sending broadcast of "
916 + ACCOUNTS_CHANGED_INTENT.getAction());
917 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700918 }
919
920 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700921 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
922 throws RemoteException {
923 try {
924 return super.onTransact(code, data, reply, flags);
925 } catch (RuntimeException e) {
926 // The account manager only throws security exceptions, so let's
927 // log all others.
928 if (!(e instanceof SecurityException)) {
929 Slog.wtf(TAG, "Account Manager Crash", e);
930 }
931 throw e;
932 }
933 }
934
Amith Yamasani258848d2012-08-10 17:06:33 -0700935 private UserManager getUserManager() {
936 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700937 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700938 }
939 return mUserManager;
940 }
941
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700942 /**
943 * Validate internal set of accounts against installed authenticators for
944 * given user. Clears cached authenticators before validating.
945 */
946 public void validateAccounts(int userId) {
947 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700948 // Invalidate user-specific cache to make sure we catch any
949 // removed authenticators.
950 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
951 }
952
953 /**
954 * Validate internal set of accounts against installed authenticators for
955 * given user. Clear cached authenticators before validating when requested.
956 */
957 private void validateAccountsInternal(
958 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700959 if (Log.isLoggable(TAG, Log.DEBUG)) {
960 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700961 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600962 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700963 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700964
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700965 if (invalidateAuthenticatorCache) {
966 mAuthenticatorCache.invalidateCache(accounts.userId);
967 }
968
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700969 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
970 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700971 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700972
Amith Yamasani04e0d262012-02-14 11:50:53 -0800973 synchronized (accounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800974 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800975
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700976 // Get a map of stored authenticator types to UID
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700977 final AccountsDb accountsDb = accounts.accountsDb;
978 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800979 // Create a list of authenticator type whose previous uid no longer exists
980 HashSet<String> obsoleteAuthType = Sets.newHashSet();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700981 SparseBooleanArray knownUids = null;
982 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
983 String type = authToUidEntry.getKey();
984 int uid = authToUidEntry.getValue();
985 Integer knownUid = knownAuth.get(type);
986 if (knownUid != null && uid == knownUid) {
987 // Remove it from the knownAuth list if it's unchanged.
988 knownAuth.remove(type);
989 } else {
990 /*
991 * The authenticator is presently not cached and should only be triggered
992 * when we think an authenticator has been removed (or is being updated).
993 * But we still want to check if any data with the associated uid is
994 * around. This is an (imperfect) signal that the package may be updating.
995 *
996 * A side effect of this is that an authenticator sharing a uid with
997 * multiple apps won't get its credentials wiped as long as some app with
998 * that uid is still on the device. But I suspect that this is a rare case.
999 * And it isn't clear to me how an attacker could really exploit that
1000 * feature.
1001 *
1002 * The upshot is that we don't have to worry about accounts getting
1003 * uninstalled while the authenticator's package is being updated.
1004 *
1005 */
1006 if (knownUids == null) {
1007 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001008 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001009 if (!knownUids.get(uid)) {
1010 // The authenticator is not presently available to the cache. And the
1011 // package no longer has a data directory (so we surmise it isn't updating).
1012 // So purge its data from the account databases.
1013 obsoleteAuthType.add(type);
1014 // And delete it from the TABLE_META
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001015 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001016 }
1017 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001018 }
1019
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001020 // Add the newly registered authenticator to TABLE_META. If old authenticators have
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001021 // been re-enabled (after being updated for example), then we just overwrite the old
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001022 // values.
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001023 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001024 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001025 }
1026
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001027 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001028 try {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001029 accounts.accountCache.clear();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001030 final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001031 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
1032 final long accountId = accountEntry.getKey();
1033 final Account account = accountEntry.getValue();
1034 if (obsoleteAuthType.contains(account.type)) {
1035 Slog.w(TAG, "deleting account " + account.name + " because type "
1036 + account.type + "'s registered authenticator no longer exist.");
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001037 Map<String, Integer> packagesToVisibility =
1038 getRequestingPackages(account, accounts);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001039 accountsDb.beginTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001040 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001041 accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001042 // Also delete from CE table if user is unlocked; if user is currently
1043 // locked the account will be removed later by syncDeCeAccountsLocked
1044 if (userUnlocked) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001045 accountsDb.deleteCeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001046 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001047 accountsDb.setTransactionSuccessful();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001048 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001049 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -07001050 }
Fred Quintana56285a62010-12-02 14:20:51 -08001051 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001052
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001053 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
1054 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001055
Amith Yamasani04e0d262012-02-14 11:50:53 -08001056 accounts.userDataCache.remove(account);
1057 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07001058 accounts.accountTokenCaches.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001059 accounts.visibilityCache.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001060
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001061 for (Entry<String, Integer> packageToVisibility :
1062 packagesToVisibility.entrySet()) {
1063 if (packageToVisibility.getValue()
1064 != AccountManager.VISIBILITY_NOT_VISIBLE) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001065 notifyPackage(packageToVisibility.getKey(), accounts);
1066 }
1067 }
Fred Quintana56285a62010-12-02 14:20:51 -08001068 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001069 ArrayList<String> accountNames = accountNamesByType.get(account.type);
Fred Quintana56285a62010-12-02 14:20:51 -08001070 if (accountNames == null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07001071 accountNames = new ArrayList<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001072 accountNamesByType.put(account.type, accountNames);
Fred Quintana56285a62010-12-02 14:20:51 -08001073 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001074 accountNames.add(account.name);
Fred Quintana56285a62010-12-02 14:20:51 -08001075 }
1076 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001077 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
Fred Quintana56285a62010-12-02 14:20:51 -08001078 final String accountType = cur.getKey();
1079 final ArrayList<String> accountNames = cur.getValue();
1080 final Account[] accountsForType = new Account[accountNames.size()];
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001081 for (int i = 0; i < accountsForType.length; i++) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07001082 accountsForType[i] = new Account(accountNames.get(i), accountType,
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001083 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001084 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001085 accounts.accountCache.put(accountType, accountsForType);
Fred Quintanaafa92b82009-12-01 16:27:03 -08001086 }
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001087 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues());
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001088 } finally {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001089 if (accountDeleted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001090 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001091 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001092 }
1093 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001094 }
1095
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001096 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1097 // Get the UIDs of all apps that might have data on the device. We want
1098 // to preserve user data if the app might otherwise be storing data.
1099 List<PackageInfo> pkgsWithData =
1100 mPackageManager.getInstalledPackagesAsUser(
1101 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1102 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1103 for (PackageInfo pkgInfo : pkgsWithData) {
1104 if (pkgInfo.applicationInfo != null
1105 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1106 knownUids.put(pkgInfo.applicationInfo.uid, true);
1107 }
1108 }
1109 return knownUids;
1110 }
1111
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001112 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001113 Context context,
1114 int userId) {
1115 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001116 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1117 }
1118
1119 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1120 IAccountAuthenticatorCache authCache,
1121 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001122 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001123 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1124 .getAllServices(userId)) {
1125 knownAuth.put(service.type.type, service.uid);
1126 }
1127 return knownAuth;
1128 }
1129
Amith Yamasani04e0d262012-02-14 11:50:53 -08001130 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001131 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001132 }
1133
1134 protected UserAccounts getUserAccounts(int userId) {
1135 synchronized (mUsers) {
1136 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001137 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001138 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001139 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1140 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001141 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001142 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001143 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001144 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001145 validateAccounts = true;
1146 }
1147 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001148 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001149 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
1150 synchronized (accounts.cacheLock) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001151 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001152 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001153 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001154 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001155 }
1156 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001157 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001158 }
1159 return accounts;
1160 }
1161 }
1162
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001163 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1164 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001165 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001166 if (!accountsToRemove.isEmpty()) {
1167 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1168 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001169 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1170 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001171
1172 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001173 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001174 }
1175 }
1176 }
1177
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001178 private void purgeOldGrantsAll() {
1179 synchronized (mUsers) {
1180 for (int i = 0; i < mUsers.size(); i++) {
1181 purgeOldGrants(mUsers.valueAt(i));
1182 }
1183 }
1184 }
1185
1186 private void purgeOldGrants(UserAccounts accounts) {
1187 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001188 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001189 for (int uid : uids) {
1190 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1191 if (packageExists) {
1192 continue;
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001193 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001194 Log.d(TAG, "deleting grants for UID " + uid
1195 + " because its package is no longer installed");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001196 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001197 }
1198 }
1199 }
1200
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001201 private void removeVisibilityValuesForPackage(String packageName) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001202 if (isSpecialPackageKey(packageName)) {
1203 return;
1204 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001205 synchronized (mUsers) {
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001206 int numberOfUsers = mUsers.size();
1207 for (int i = 0; i < numberOfUsers; i++) {
1208 UserAccounts accounts = mUsers.valueAt(i);
1209 try {
1210 mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1211 } catch (NameNotFoundException e) {
1212 // package does not exist - remove visibility values
1213 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
1214 synchronized(accounts.cacheLock) {
1215 for (Account account : accounts.visibilityCache.keySet()) {
1216 Map<String, Integer> accountVisibility =
1217 getPackagesAndVisibilityForAccountLocked(account, accounts);
1218 accountVisibility.remove(packageName);
1219 }
1220 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001221 }
1222 }
1223 }
1224 }
1225
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001226
Fyodor Kupolovb9da4e42017-03-16 13:01:12 -07001227 private void onCleanupUser(int userId) {
1228 Log.i(TAG, "onCleanupUser " + userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001229 UserAccounts accounts;
1230 synchronized (mUsers) {
1231 accounts = mUsers.get(userId);
1232 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001233 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001234 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001235 if (accounts != null) {
1236 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001237 accounts.accountsDb.close();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001238 }
Amith Yamasani13593602012-03-22 16:16:17 -07001239 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001240 }
1241
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001242 @VisibleForTesting
1243 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001244 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1245 }
1246
1247 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001248 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1249 Log.v(TAG, "onUserUnlocked " + userId);
1250 }
1251 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001252 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001253 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001254 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001255 syncSharedAccounts(userId);
1256 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001257
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001258 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001259 // Check if there's a shared account that needs to be created as an account
1260 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1261 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001262 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001263 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001264 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001265 : UserHandle.USER_SYSTEM;
1266 if (parentUserId < 0) {
1267 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1268 return;
1269 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001270 for (Account sa : sharedAccounts) {
1271 if (ArrayUtils.contains(accounts, sa)) continue;
1272 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001273 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001274 }
1275 }
1276
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001277 @Override
1278 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001279 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001280 }
1281
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001282 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001283 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001284 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001285 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1286 Log.v(TAG, "getPassword: " + account
1287 + ", caller's uid " + Binder.getCallingUid()
1288 + ", pid " + Binder.getCallingPid());
1289 }
Fred Quintana382601f2010-03-25 12:25:10 -07001290 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001291 int userId = UserHandle.getCallingUserId();
1292 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001293 String msg = String.format(
1294 "uid %s cannot get secrets for accounts of type: %s",
1295 callingUid,
1296 account.type);
1297 throw new SecurityException(msg);
1298 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001299 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001300 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001301 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001302 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001303 } finally {
1304 restoreCallingIdentity(identityToken);
1305 }
1306 }
1307
Amith Yamasani04e0d262012-02-14 11:50:53 -08001308 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001309 if (account == null) {
1310 return null;
1311 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001312 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001313 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1314 return null;
1315 }
Fred Quintana31957f12009-10-21 13:43:10 -07001316
Amith Yamasani04e0d262012-02-14 11:50:53 -08001317 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001318 return accounts.accountsDb.findAccountPasswordByNameAndType(account.name, account.type);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001319 }
1320 }
1321
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001322 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001323 public String getPreviousName(Account account) {
1324 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1325 Log.v(TAG, "getPreviousName: " + account
1326 + ", caller's uid " + Binder.getCallingUid()
1327 + ", pid " + Binder.getCallingPid());
1328 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001329 Preconditions.checkNotNull(account, "account cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001330 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001331 long identityToken = clearCallingIdentity();
1332 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001333 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001334 return readPreviousNameInternal(accounts, account);
1335 } finally {
1336 restoreCallingIdentity(identityToken);
1337 }
1338 }
1339
1340 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1341 if (account == null) {
1342 return null;
1343 }
1344 synchronized (accounts.cacheLock) {
1345 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1346 if (previousNameRef == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001347 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001348 previousNameRef = new AtomicReference<>(previousName);
1349 accounts.previousNameCache.put(account, previousNameRef);
1350 return previousName;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001351 } else {
1352 return previousNameRef.get();
1353 }
1354 }
1355 }
1356
1357 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001358 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001359 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001360 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001361 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1362 account, key, callingUid, Binder.getCallingPid());
1363 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001364 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001365 Preconditions.checkNotNull(account, "account cannot be null");
1366 Preconditions.checkNotNull(key, "key cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001367 int userId = UserHandle.getCallingUserId();
1368 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001369 String msg = String.format(
1370 "uid %s cannot get user data for accounts of type: %s",
1371 callingUid,
1372 account.type);
1373 throw new SecurityException(msg);
1374 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001375 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001376 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1377 return null;
1378 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001379 long identityToken = clearCallingIdentity();
1380 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001381 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00001382 synchronized (accounts.cacheLock) {
1383 if (!accountExistsCacheLocked(accounts, account)) {
1384 return null;
1385 }
1386 return readUserDataInternalLocked(accounts, account, key);
1387 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001388 } finally {
1389 restoreCallingIdentity(identityToken);
1390 }
1391 }
1392
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001393 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001394 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001395 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001396 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1397 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001398 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001399 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001400 + ", pid " + Binder.getCallingPid());
1401 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001402 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001403 if (isCrossUser(callingUid, userId)) {
1404 throw new SecurityException(
1405 String.format(
1406 "User %s tying to get authenticator types for %s" ,
1407 UserHandle.getCallingUserId(),
1408 userId));
1409 }
1410
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001411 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001412 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001413 return getAuthenticatorTypesInternal(userId);
1414
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001415 } finally {
1416 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001417 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001418 }
1419
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001420 /**
1421 * Should only be called inside of a clearCallingIdentity block.
1422 */
1423 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001424 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001425 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1426 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1427 AuthenticatorDescription[] types =
1428 new AuthenticatorDescription[authenticatorCollection.size()];
1429 int i = 0;
1430 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1431 : authenticatorCollection) {
1432 types[i] = authenticator.type;
1433 i++;
1434 }
1435 return types;
1436 }
1437
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001438 private boolean isCrossUser(int callingUid, int userId) {
1439 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001440 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001441 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001442 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1443 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001444 }
1445
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001446 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001447 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001448 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001449 }
1450
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001451 @Override
1452 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001453 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001454 int callingUid = Binder.getCallingUid();
1455 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1456 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001457 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001458 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001459 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1460 final UserAccounts toAccounts = getUserAccounts(userTo);
1461 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001462 if (response != null) {
1463 Bundle result = new Bundle();
1464 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1465 try {
1466 response.onResult(result);
1467 } catch (RemoteException e) {
1468 Slog.w(TAG, "Failed to report error back to the client." + e);
1469 }
1470 }
1471 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001472 }
1473
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001474 Slog.d(TAG, "Copying account " + account.name
1475 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001476 long identityToken = clearCallingIdentity();
1477 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001478 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001479 false /* stripAuthTokenFromResult */, account.name,
1480 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001481 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001482 protected String toDebugString(long now) {
1483 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1484 + ", " + account.type;
1485 }
1486
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001487 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001488 public void run() throws RemoteException {
1489 mAuthenticator.getAccountCredentialsForCloning(this, account);
1490 }
1491
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001492 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001493 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001494 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001495 if (result != null
1496 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1497 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001498 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001499 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001500 super.onResult(result);
1501 }
1502 }
1503 }.bind();
1504 } finally {
1505 restoreCallingIdentity(identityToken);
1506 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001507 }
1508
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001509 @Override
1510 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001511 final int callingUid = Binder.getCallingUid();
1512 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1513 String msg = String.format(
1514 "accountAuthenticated( account: %s, callerUid: %s)",
1515 account,
1516 callingUid);
1517 Log.v(TAG, msg);
1518 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001519 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001520 int userId = UserHandle.getCallingUserId();
1521 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001522 String msg = String.format(
1523 "uid %s cannot notify authentication for accounts of type: %s",
1524 callingUid,
1525 account.type);
1526 throw new SecurityException(msg);
1527 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001528
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001529 if (!canUserModifyAccounts(userId, callingUid) ||
1530 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001531 return false;
1532 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001533
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001534 long identityToken = clearCallingIdentity();
1535 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001536 UserAccounts accounts = getUserAccounts(userId);
1537 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001538 } finally {
1539 restoreCallingIdentity(identityToken);
1540 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001541 }
1542
1543 private boolean updateLastAuthenticatedTime(Account account) {
1544 final UserAccounts accounts = getUserAccountsForCaller();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001545 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001546 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001547 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001548 }
1549
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001550 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001551 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1552 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001553 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001554 long id = clearCallingIdentity();
1555 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001556 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001557 false /* stripAuthTokenFromResult */, account.name,
1558 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001559 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001560 protected String toDebugString(long now) {
1561 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1562 + ", " + account.type;
1563 }
1564
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001565 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001566 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001567 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001568 UserAccounts owner = getUserAccounts(parentUserId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001569 synchronized (owner.cacheLock) {
Svetoslavf3f02ac2015-09-08 14:36:35 -07001570 for (Account acc : getAccounts(parentUserId,
1571 mContext.getOpPackageName())) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001572 if (acc.equals(account)) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001573 mAuthenticator.addAccountFromCredentials(
1574 this, account, accountCredentials);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001575 break;
1576 }
1577 }
1578 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001579 }
1580
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001581 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001582 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001583 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001584 // TODO: Anything to do if if succedded?
1585 // TODO: If it failed: Show error notification? Should we remove the shadow
1586 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001587 // TODO: what we do with the visibility?
1588
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001589 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001590 }
1591
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001592 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001593 public void onError(int errorCode, String errorMessage) {
1594 super.onError(errorCode, errorMessage);
1595 // TODO: Show error notification to user
1596 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1597 }
1598
1599 }.bind();
1600 } finally {
1601 restoreCallingIdentity(id);
1602 }
1603 }
1604
Amith Yamasani04e0d262012-02-14 11:50:53 -08001605 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001606 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001607 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001608 if (account == null) {
1609 return false;
1610 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001611 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001612 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1613 + " is locked. callingUid=" + callingUid);
1614 return false;
1615 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001616 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001617 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001618 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001619 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001620 Log.w(TAG, "insertAccountIntoDatabase: " + account
1621 + ", skipping since the account already exists");
1622 return false;
1623 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001624 long accountId = accounts.accountsDb.insertCeAccount(account, password);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001625 if (accountId < 0) {
1626 Log.w(TAG, "insertAccountIntoDatabase: " + account
1627 + ", skipping the DB insert failed");
1628 return false;
1629 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001630 // Insert into DE table
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001631 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001632 Log.w(TAG, "insertAccountIntoDatabase: " + account
1633 + ", skipping the DB insert failed");
1634 return false;
1635 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001636 if (extras != null) {
1637 for (String key : extras.keySet()) {
1638 final String value = extras.getString(key);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001639 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001640 Log.w(TAG, "insertAccountIntoDatabase: " + account
1641 + ", skipping since insertExtra failed for key " + key);
1642 return false;
1643 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001644 }
1645 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001646
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001647 if (packageToVisibility != null) {
1648 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1649 setAccountVisibility(account, entry.getKey() /* package */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001650 entry.getValue() /* visibility */, false /* notify */, accounts);
1651 }
1652 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001653 accounts.accountsDb.setTransactionSuccessful();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001654
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001655 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
1656 accounts, callingUid);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001657
Amith Yamasani04e0d262012-02-14 11:50:53 -08001658 insertAccountIntoCacheLocked(accounts, account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001659 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001660 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001661 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001662 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001663 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1664 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001665 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001666
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001667 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001668 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1669 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001670
Amith Yamasani5be347b2013-03-31 17:44:31 -07001671 return true;
1672 }
1673
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001674 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001675 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001676 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001677 }
1678 }
1679
Amith Yamasani5be347b2013-03-31 17:44:31 -07001680 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001681 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001682 * running, then clone the account too.
1683 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001684 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001685 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001686 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001687 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001688 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001689 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001690 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001691 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001692 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001693 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001694 }
1695 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001696 }
1697 }
1698
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001699 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001700 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001701 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001702 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001703 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001704 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1705 Log.v(TAG, "hasFeatures: " + account
1706 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001707 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001708 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001709 + ", pid " + Binder.getCallingPid());
1710 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001711 Preconditions.checkArgument(account != null, "account cannot be null");
1712 Preconditions.checkArgument(response != null, "response cannot be null");
1713 Preconditions.checkArgument(features != null, "features cannot be null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001714 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001715 checkReadAccountsPermitted(callingUid, account.type, userId,
1716 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001717
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001718 long identityToken = clearCallingIdentity();
1719 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001720 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001721 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001722 } finally {
1723 restoreCallingIdentity(identityToken);
1724 }
1725 }
1726
1727 private class TestFeaturesSession extends Session {
1728 private final String[] mFeatures;
1729 private final Account mAccount;
1730
Amith Yamasani04e0d262012-02-14 11:50:53 -08001731 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001732 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001733 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001734 true /* stripAuthTokenFromResult */, account.name,
1735 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001736 mFeatures = features;
1737 mAccount = account;
1738 }
1739
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001740 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001741 public void run() throws RemoteException {
1742 try {
1743 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1744 } catch (RemoteException e) {
1745 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1746 }
1747 }
1748
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001749 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001750 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001751 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001752 IAccountManagerResponse response = getResponseAndClose();
1753 if (response != null) {
1754 try {
1755 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001756 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001757 return;
1758 }
Fred Quintana56285a62010-12-02 14:20:51 -08001759 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1760 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1761 + response);
1762 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001763 final Bundle newResult = new Bundle();
1764 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1765 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1766 response.onResult(newResult);
1767 } catch (RemoteException e) {
1768 // if the caller is dead then there is no one to care about remote exceptions
1769 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1770 Log.v(TAG, "failure while notifying response", e);
1771 }
1772 }
1773 }
1774 }
1775
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001776 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001777 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001778 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001779 + ", " + mAccount
1780 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1781 }
1782 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001783
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001784 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001785 public void renameAccount(
1786 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001787 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001788 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1789 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001790 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001791 + ", pid " + Binder.getCallingPid());
1792 }
1793 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001794 int userId = UserHandle.getCallingUserId();
1795 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001796 String msg = String.format(
1797 "uid %s cannot rename accounts of type: %s",
1798 callingUid,
1799 accountToRename.type);
1800 throw new SecurityException(msg);
1801 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001802 long identityToken = clearCallingIdentity();
1803 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001804 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001805 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001806 Bundle result = new Bundle();
1807 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1808 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001809 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1810 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001811 try {
1812 response.onResult(result);
1813 } catch (RemoteException e) {
1814 Log.w(TAG, e.getMessage());
1815 }
1816 } finally {
1817 restoreCallingIdentity(identityToken);
1818 }
1819 }
1820
1821 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001822 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001823 Account resultAccount = null;
1824 /*
1825 * Cancel existing notifications. Let authenticators
1826 * re-post notifications as required. But we don't know if
1827 * the authenticators have bound their notifications to
1828 * now stale account name data.
1829 *
1830 * With a rename api, we might not need to do this anymore but it
1831 * shouldn't hurt.
1832 */
1833 cancelNotification(
1834 getSigninRequiredNotificationId(accounts, accountToRename),
1835 new UserHandle(accounts.userId));
1836 synchronized(accounts.credentialsPermissionNotificationIds) {
1837 for (Pair<Pair<Account, String>, Integer> pair:
1838 accounts.credentialsPermissionNotificationIds.keySet()) {
1839 if (accountToRename.equals(pair.first.first)) {
1840 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1841 cancelNotification(id, new UserHandle(accounts.userId));
1842 }
1843 }
1844 }
1845 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001846 accounts.accountsDb.beginTransaction();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001847 Account renamedAccount = new Account(newName, accountToRename.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001848 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1849 Log.e(TAG, "renameAccount failed - account with new name already exists");
1850 return null;
1851 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001852 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001853 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001854 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001855 accounts.accountsDb.renameCeAccount(accountId, newName);
Dmitry Dementyevcf50dcf2016-11-17 14:14:11 -08001856 if (accounts.accountsDb.renameDeAccount(
1857 accountId, newName, accountToRename.name)) {
1858 accounts.accountsDb.setTransactionSuccessful();
1859 } else {
1860 Log.e(TAG, "renameAccount failed");
1861 return null;
1862 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001863 } else {
1864 Log.e(TAG, "renameAccount failed - old account does not exist");
1865 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001866 }
1867 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001868 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001869 }
1870 /*
1871 * Database transaction was successful. Clean up cached
1872 * data associated with the account in the user profile.
1873 */
Svet Ganov5c4a5122016-09-23 19:29:11 -07001874 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001875 /*
1876 * Extract the data and token caches before removing the
1877 * old account to preserve the user data associated with
1878 * the account.
1879 */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001880 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1881 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001882 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001883 removeAccountFromCacheLocked(accounts, accountToRename);
1884 /*
1885 * Update the cached data associated with the renamed
1886 * account.
1887 */
1888 accounts.userDataCache.put(renamedAccount, tmpData);
1889 accounts.authTokenCache.put(renamedAccount, tmpTokens);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07001890 accounts.visibilityCache.put(renamedAccount, tmpVisibility);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001891 accounts.previousNameCache.put(
1892 renamedAccount,
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001893 new AtomicReference<>(accountToRename.name));
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001894 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001895
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001896 int parentUserId = accounts.userId;
1897 if (canHaveProfile(parentUserId)) {
1898 /*
1899 * Owner or system user account was renamed, rename the account for
1900 * those users with which the account was shared.
1901 */
1902 List<UserInfo> users = getUserManager().getUsers(true);
1903 for (UserInfo user : users) {
1904 if (user.isRestricted()
1905 && (user.restrictedProfileParentId == parentUserId)) {
1906 renameSharedAccountAsUser(accountToRename, newName, user.id);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001907 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001908 }
1909 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001910
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001911 sendNotificationAccountUpdated(resultAccount, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001912 sendAccountsChangedBroadcast(accounts.userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001913 }
1914 return resultAccount;
1915 }
1916
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001917 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001918 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001919 return userInfo != null && userInfo.canHaveProfile();
1920 }
1921
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001922 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001923 public void removeAccount(IAccountManagerResponse response, Account account,
1924 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001925 removeAccountAsUser(
1926 response,
1927 account,
1928 expectActivityLaunch,
1929 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001930 }
1931
1932 @Override
1933 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001934 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001935 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001936 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1937 Log.v(TAG, "removeAccount: " + account
1938 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001939 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001940 + ", pid " + Binder.getCallingPid()
1941 + ", for user id " + userId);
1942 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07001943 Preconditions.checkArgument(account != null, "account cannot be null");
1944 Preconditions.checkArgument(response != null, "response cannot be null");
1945
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001946 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001947 if (isCrossUser(callingUid, userId)) {
1948 throw new SecurityException(
1949 String.format(
1950 "User %s tying remove account for %s" ,
1951 UserHandle.getCallingUserId(),
1952 userId));
1953 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001954 /*
1955 * Only the system or authenticator should be allowed to remove accounts for that
1956 * authenticator. This will let users remove accounts (via Settings in the system) but not
1957 * arbitrary applications (like competing authenticators).
1958 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001959 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00001960 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1961 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001962 String msg = String.format(
1963 "uid %s cannot remove accounts of type: %s",
1964 callingUid,
1965 account.type);
1966 throw new SecurityException(msg);
1967 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001968 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001969 try {
1970 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
1971 "User cannot modify accounts");
1972 } catch (RemoteException re) {
1973 }
1974 return;
1975 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001976 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001977 try {
1978 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
1979 "User cannot modify accounts of this type (policy).");
1980 } catch (RemoteException re) {
1981 }
1982 return;
1983 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001984 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001985 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001986 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001987 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001988 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08001989 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001990 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001991 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001992 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001993 }
1994 }
1995 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001996 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001997 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001998 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1999 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002000 accountId,
2001 accounts,
2002 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002003 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002004 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
2005 } finally {
2006 restoreCallingIdentity(identityToken);
2007 }
2008 }
2009
2010 @Override
2011 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002012 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002013 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2014 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002015 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002016 + ", pid " + Binder.getCallingPid());
2017 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002018 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002019 if (account == null) {
2020 /*
2021 * Null accounts should result in returning false, as per
2022 * AccountManage.addAccountExplicitly(...) java doc.
2023 */
2024 Log.e(TAG, "account is null");
2025 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002026 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002027 String msg = String.format(
2028 "uid %s cannot explicitly add accounts of type: %s",
2029 callingUid,
2030 account.type);
2031 throw new SecurityException(msg);
2032 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002033 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002034 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002035 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002036 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
2037 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07002038 accountId,
2039 accounts,
2040 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002041 long identityToken = clearCallingIdentity();
2042 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002043 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002044 } finally {
2045 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07002046 }
Fred Quintana60307342009-03-24 22:48:12 -07002047 }
2048
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002049 private class RemoveAccountSession extends Session {
2050 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002051 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08002052 Account account, boolean expectActivityLaunch) {
2053 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002054 true /* stripAuthTokenFromResult */, account.name,
2055 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002056 mAccount = account;
2057 }
2058
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002059 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002060 protected String toDebugString(long now) {
2061 return super.toDebugString(now) + ", removeAccount"
2062 + ", account " + mAccount;
2063 }
2064
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002065 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002066 public void run() throws RemoteException {
2067 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
2068 }
2069
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002070 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002071 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002072 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002073 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
2074 && !result.containsKey(AccountManager.KEY_INTENT)) {
2075 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002076 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002077 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002078 }
2079 IAccountManagerResponse response = getResponseAndClose();
2080 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002081 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2082 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2083 + response);
2084 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002085 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002086 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002087 try {
2088 response.onResult(result2);
2089 } catch (RemoteException e) {
2090 // ignore
2091 }
2092 }
2093 }
2094 super.onResult(result);
2095 }
2096 }
2097
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002098 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002099 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002100 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002101 }
2102
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002103 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002104 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002105 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002106 if (!userUnlocked) {
2107 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2108 + " is still locked. CE data will be removed later");
2109 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08002110 synchronized (accounts.cacheLock) {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002111 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002112 accounts.accountsDb.beginTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002113 // Set to a dummy value, this will only be used if the database
2114 // transaction succeeds.
2115 long accountId = -1;
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002116 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002117 accountId = accounts.accountsDb.findDeAccountId(account);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002118 if (accountId >= 0) {
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002119 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002120 }
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002121 // always delete from CE table if CE storage is available
2122 // DE account could be removed while CE was locked
2123 if (userUnlocked) {
2124 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2125 if (ceAccountId >= 0) {
2126 accounts.accountsDb.deleteCeAccount(ceAccountId);
2127 }
2128 }
2129 accounts.accountsDb.setTransactionSuccessful();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002130 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002131 accounts.accountsDb.endTransaction();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002132 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002133 if (isChanged) {
2134 removeAccountFromCacheLocked(accounts, account);
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002135 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
2136 if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
2137 notifyPackage(packageToVisibility.getKey(), accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002138 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002139 }
2140
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002141 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002142 sendAccountsChangedBroadcast(accounts.userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002143 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2144 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2145 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002146 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002147 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002148 long id = Binder.clearCallingIdentity();
2149 try {
2150 int parentUserId = accounts.userId;
2151 if (canHaveProfile(parentUserId)) {
2152 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002153 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002154 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002155 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002156 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002157 }
2158 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002159 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002160 } finally {
2161 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002162 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002163
2164 if (isChanged) {
2165 synchronized (accounts.credentialsPermissionNotificationIds) {
2166 for (Pair<Pair<Account, String>, Integer> key
2167 : accounts.credentialsPermissionNotificationIds.keySet()) {
2168 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002169 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002170 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002171 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002172 account, uid, false));
2173 }
2174 }
2175 }
2176 }
2177
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002178 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002179 }
2180
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002181 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002182 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002183 int callerUid = Binder.getCallingUid();
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002184 Preconditions.checkNotNull(accountType, "accountType cannot be null");
2185 Preconditions.checkNotNull(authToken, "authToken cannot be null");
Fred Quintana56285a62010-12-02 14:20:51 -08002186 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2187 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002188 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002189 + ", pid " + Binder.getCallingPid());
2190 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002191 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002192 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002193 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002194 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002195 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002196 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002197 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002198 invalidateAuthTokenLocked(accounts, accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002199 invalidateCustomTokenLocked(accounts, accountType, authToken);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002200 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002201 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002202 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002203 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002204 }
Fred Quintana60307342009-03-24 22:48:12 -07002205 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002206 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002207 }
2208 }
2209
Carlos Valdivia91979be2015-05-22 14:11:35 -07002210 private void invalidateCustomTokenLocked(
2211 UserAccounts accounts,
2212 String accountType,
2213 String authToken) {
2214 if (authToken == null || accountType == null) {
2215 return;
2216 }
2217 // Also wipe out cached token in memory.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002218 accounts.accountTokenCaches.remove(accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002219 }
2220
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002221 private void invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
2222 String authToken) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002223 if (authToken == null || accountType == null) {
2224 return;
2225 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002226 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fred Quintana33269202009-04-20 16:05:10 -07002227 try {
2228 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002229 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002230 String accountName = cursor.getString(1);
2231 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002232 accounts.accountsDb.deleteAuthToken(authTokenId);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002233 writeAuthTokenIntoCacheLocked(
2234 accounts,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002235 new Account(accountName, accountType),
2236 authTokenType,
2237 null);
Fred Quintana60307342009-03-24 22:48:12 -07002238 }
Fred Quintana33269202009-04-20 16:05:10 -07002239 } finally {
2240 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002241 }
2242 }
2243
Carlos Valdivia91979be2015-05-22 14:11:35 -07002244 private void saveCachedToken(
2245 UserAccounts accounts,
2246 Account account,
2247 String callerPkg,
2248 byte[] callerSigDigest,
2249 String tokenType,
2250 String token,
2251 long expiryMillis) {
2252
2253 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2254 return;
2255 }
2256 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002257 UserHandle.of(accounts.userId));
Carlos Valdivia91979be2015-05-22 14:11:35 -07002258 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002259 accounts.accountTokenCaches.put(
2260 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002261 }
2262 }
2263
Amith Yamasani04e0d262012-02-14 11:50:53 -08002264 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2265 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002266 if (account == null || type == null) {
2267 return false;
2268 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002269 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002270 UserHandle.of(accounts.userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002271 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002272 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002273 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002274 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002275 if (accountId < 0) {
2276 return false;
2277 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002278 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2279 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2280 accounts.accountsDb.setTransactionSuccessful();
2281 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002282 return true;
2283 }
Fred Quintana33269202009-04-20 16:05:10 -07002284 return false;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002285 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002286 accounts.accountsDb.endTransaction();
Fred Quintana33269202009-04-20 16:05:10 -07002287 }
Fred Quintana60307342009-03-24 22:48:12 -07002288 }
2289 }
2290
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002291 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002292 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002293 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002294 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2295 Log.v(TAG, "peekAuthToken: " + account
2296 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002297 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002298 + ", pid " + Binder.getCallingPid());
2299 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002300 Preconditions.checkNotNull(account, "account cannot be null");
2301 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002302 int userId = UserHandle.getCallingUserId();
2303 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002304 String msg = String.format(
2305 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2306 callingUid,
2307 account.type);
2308 throw new SecurityException(msg);
2309 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002310 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002311 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2312 + callingUid);
2313 return null;
2314 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002315 long identityToken = clearCallingIdentity();
2316 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002317 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002318 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002319 } finally {
2320 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002321 }
Fred Quintana60307342009-03-24 22:48:12 -07002322 }
2323
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002324 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002325 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002326 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002327 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2328 Log.v(TAG, "setAuthToken: " + account
2329 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002330 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002331 + ", pid " + Binder.getCallingPid());
2332 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002333 Preconditions.checkNotNull(account, "account cannot be null");
2334 Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002335 int userId = UserHandle.getCallingUserId();
2336 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002337 String msg = String.format(
2338 "uid %s cannot set auth tokens associated with accounts of type: %s",
2339 callingUid,
2340 account.type);
2341 throw new SecurityException(msg);
2342 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002343 long identityToken = clearCallingIdentity();
2344 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002345 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002346 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002347 } finally {
2348 restoreCallingIdentity(identityToken);
2349 }
Fred Quintana60307342009-03-24 22:48:12 -07002350 }
2351
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002352 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002353 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002354 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002355 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2356 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002357 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002358 + ", pid " + Binder.getCallingPid());
2359 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002360 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002361 int userId = UserHandle.getCallingUserId();
2362 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002363 String msg = String.format(
2364 "uid %s cannot set secrets for accounts of type: %s",
2365 callingUid,
2366 account.type);
2367 throw new SecurityException(msg);
2368 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002369 long identityToken = clearCallingIdentity();
2370 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002371 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002372 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002373 } finally {
2374 restoreCallingIdentity(identityToken);
2375 }
Fred Quintana60307342009-03-24 22:48:12 -07002376 }
2377
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002378 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2379 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002380 if (account == null) {
2381 return;
2382 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002383 boolean isChanged = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002384 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002385 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002386 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002387 final long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002388 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002389 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2390 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002391 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002392 accounts.accountTokenCaches.remove(account);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002393 accounts.accountsDb.setTransactionSuccessful();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002394 // If there is an account whose password will be updated and the database
2395 // transactions succeed, then we say that a change has occured. Even if the
2396 // new password is the same as the old and there were no authtokens to delete.
2397 isChanged = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002398 String action = (password == null || password.length() == 0) ?
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002399 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2400 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2401 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
Costin Manolachef5ffe892011-01-19 09:35:32 -08002402 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002403 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002404 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002405 if (isChanged) {
2406 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002407 sendNotificationAccountUpdated(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002408 sendAccountsChangedBroadcast(accounts.userId);
2409 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002410 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002411 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002412 }
2413
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002414 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002415 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002416 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002417 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2418 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002419 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002420 + ", pid " + Binder.getCallingPid());
2421 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002422 Preconditions.checkNotNull(account, "account cannot be null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002423 int userId = UserHandle.getCallingUserId();
2424 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002425 String msg = String.format(
2426 "uid %s cannot clear passwords for accounts of type: %s",
2427 callingUid,
2428 account.type);
2429 throw new SecurityException(msg);
2430 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002431 long identityToken = clearCallingIdentity();
2432 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002433 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002434 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002435 } finally {
2436 restoreCallingIdentity(identityToken);
2437 }
Fred Quintana60307342009-03-24 22:48:12 -07002438 }
2439
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002440 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002441 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002442 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002443 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2444 Log.v(TAG, "setUserData: " + account
2445 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002446 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002447 + ", pid " + Binder.getCallingPid());
2448 }
Fred Quintana382601f2010-03-25 12:25:10 -07002449 if (key == null) throw new IllegalArgumentException("key is null");
2450 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002451 int userId = UserHandle.getCallingUserId();
2452 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002453 String msg = String.format(
2454 "uid %s cannot set user data for accounts of type: %s",
2455 callingUid,
2456 account.type);
2457 throw new SecurityException(msg);
2458 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002459 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002460 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002461 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002462 synchronized (accounts.cacheLock) {
2463 if (!accountExistsCacheLocked(accounts, account)) {
2464 return;
2465 }
2466 setUserdataInternalLocked(accounts, account, key, value);
2467 }
Fred Quintana60307342009-03-24 22:48:12 -07002468 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002469 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002470 }
2471 }
2472
Simranjit Kohli858511c2016-03-10 18:36:11 +00002473 private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
2474 if (accounts.accountCache.containsKey(account.type)) {
2475 for (Account acc : accounts.accountCache.get(account.type)) {
2476 if (acc.name.equals(account.name)) {
2477 return true;
2478 }
2479 }
2480 }
2481 return false;
2482 }
2483
2484 private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002485 String value) {
Fred Quintana31957f12009-10-21 13:43:10 -07002486 if (account == null || key == null) {
2487 return;
2488 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002489 accounts.accountsDb.beginTransaction();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002490 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002491 long accountId = accounts.accountsDb.findDeAccountId(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002492 if (accountId < 0) {
2493 return;
2494 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002495 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002496 if (extrasId < 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002497 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002498 if (extrasId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002499 return;
2500 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002501 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002502 return;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002503 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002504 writeUserDataIntoCacheLocked(accounts, account, key, value);
2505 accounts.accountsDb.setTransactionSuccessful();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002506 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002507 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002508 }
2509 }
2510
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002511 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002512 if (result == null) {
2513 Log.e(TAG, "the result is unexpectedly null", new Exception());
2514 }
2515 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2516 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2517 + response);
2518 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002519 try {
2520 response.onResult(result);
2521 } catch (RemoteException e) {
2522 // if the caller is dead then there is no one to care about remote
2523 // exceptions
2524 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2525 Log.v(TAG, "failure while notifying response", e);
2526 }
2527 }
2528 }
2529
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002530 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002531 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2532 final String authTokenType)
2533 throws RemoteException {
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002534 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
2535 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002536
Fred Quintanad9640ec2012-05-23 12:37:00 -07002537 final int callingUid = getCallingUid();
2538 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002539 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002540 throw new SecurityException("can only call from system");
2541 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002542 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002543 long identityToken = clearCallingIdentity();
2544 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002545 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002546 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2547 false /* stripAuthTokenFromResult */, null /* accountName */,
2548 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002549 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002550 protected String toDebugString(long now) {
2551 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002552 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002553 + ", authTokenType " + authTokenType;
2554 }
2555
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002556 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002557 public void run() throws RemoteException {
2558 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2559 }
2560
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002561 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002562 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002563 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002564 if (result != null) {
2565 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2566 Bundle bundle = new Bundle();
2567 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2568 super.onResult(bundle);
2569 return;
2570 } else {
2571 super.onResult(result);
2572 }
2573 }
2574 }.bind();
2575 } finally {
2576 restoreCallingIdentity(identityToken);
2577 }
2578 }
2579
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002580 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002581 public void getAuthToken(
2582 IAccountManagerResponse response,
2583 final Account account,
2584 final String authTokenType,
2585 final boolean notifyOnAuthFailure,
2586 final boolean expectActivityLaunch,
2587 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002588 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002589 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2590 Log.v(TAG, "getAuthToken: " + account
2591 + ", response " + response
2592 + ", authTokenType " + authTokenType
2593 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2594 + ", expectActivityLaunch " + expectActivityLaunch
2595 + ", caller's uid " + Binder.getCallingUid()
2596 + ", pid " + Binder.getCallingPid());
2597 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002598 Preconditions.checkArgument(response != null, "response cannot be null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002599 try {
2600 if (account == null) {
2601 Slog.w(TAG, "getAuthToken called with null account");
2602 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2603 return;
2604 }
2605 if (authTokenType == null) {
2606 Slog.w(TAG, "getAuthToken called with null authTokenType");
2607 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2608 return;
2609 }
2610 } catch (RemoteException e) {
2611 Slog.w(TAG, "Failed to report error back to the client." + e);
2612 return;
2613 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002614 int userId = UserHandle.getCallingUserId();
2615 long ident = Binder.clearCallingIdentity();
2616 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002617 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002618 try {
2619 accounts = getUserAccounts(userId);
2620 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2621 AuthenticatorDescription.newKey(account.type), accounts.userId);
2622 } finally {
2623 Binder.restoreCallingIdentity(ident);
2624 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002625
Costin Manolachea40c6302010-12-13 14:50:45 -08002626 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002627 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002628
2629 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002630 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002631 final boolean permissionGranted =
2632 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002633
Carlos Valdivia91979be2015-05-22 14:11:35 -07002634 // Get the calling package. We will use it for the purpose of caching.
2635 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002636 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002637 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002638 try {
2639 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2640 } finally {
2641 Binder.restoreCallingIdentity(ident);
2642 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002643 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2644 String msg = String.format(
2645 "Uid %s is attempting to illegally masquerade as package %s!",
2646 callerUid,
2647 callerPkg);
2648 throw new SecurityException(msg);
2649 }
2650
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002651 // let authenticator know the identity of the caller
2652 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2653 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002654
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002655 if (notifyOnAuthFailure) {
2656 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002657 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002658
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002659 long identityToken = clearCallingIdentity();
2660 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002661 // Distill the caller's package signatures into a single digest.
2662 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2663
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002664 // if the caller has permission, do the peek. otherwise go the more expensive
2665 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002666 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002667 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002668 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002669 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002670 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2671 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2672 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002673 onResult(response, result);
2674 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002675 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002676 }
2677
Carlos Valdivia91979be2015-05-22 14:11:35 -07002678 if (customTokens) {
2679 /*
2680 * Look up tokens in the new cache only if the loginOptions don't have parameters
2681 * outside of those expected to be injected by the AccountManager, e.g.
2682 * ANDORID_PACKAGE_NAME.
2683 */
2684 String token = readCachedTokenInternal(
2685 accounts,
2686 account,
2687 authTokenType,
2688 callerPkg,
2689 callerPkgSigDigest);
2690 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002691 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2692 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2693 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002694 Bundle result = new Bundle();
2695 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2696 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2697 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2698 onResult(response, result);
2699 return;
2700 }
2701 }
2702
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002703 new Session(
2704 accounts,
2705 response,
2706 account.type,
2707 expectActivityLaunch,
2708 false /* stripAuthTokenFromResult */,
2709 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002710 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002711 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002712 protected String toDebugString(long now) {
2713 if (loginOptions != null) loginOptions.keySet();
2714 return super.toDebugString(now) + ", getAuthToken"
2715 + ", " + account
2716 + ", authTokenType " + authTokenType
2717 + ", loginOptions " + loginOptions
2718 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2719 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002720
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002721 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002722 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002723 // If the caller doesn't have permission then create and return the
2724 // "grant permission" intent instead of the "getAuthToken" intent.
2725 if (!permissionGranted) {
2726 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2727 } else {
2728 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2729 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002730 }
2731
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002732 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002733 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002734 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002735 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002736 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002737 Intent intent = newGrantCredentialsPermissionIntent(
2738 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002739 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002740 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002741 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002742 authTokenType,
2743 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002744 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002745 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002746 onResult(bundle);
2747 return;
2748 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002749 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002750 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002751 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2752 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002753 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002754 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002755 "the type and name should not be empty");
2756 return;
2757 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002758 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002759 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002760 saveAuthTokenToDatabase(
2761 mAccounts,
2762 resultAccount,
2763 authTokenType,
2764 authToken);
2765 }
2766 long expiryMillis = result.getLong(
2767 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2768 if (customTokens
2769 && expiryMillis > System.currentTimeMillis()) {
2770 saveCachedToken(
2771 mAccounts,
2772 account,
2773 callerPkg,
2774 callerPkgSigDigest,
2775 authTokenType,
2776 authToken,
2777 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002778 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002779 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002780
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002781 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002782 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002783 /*
2784 * Make sure that the supplied intent is owned by the authenticator
2785 * giving it to the system. Otherwise a malicious authenticator could
2786 * have users launching arbitrary activities by tricking users to
2787 * interact with malicious notifications.
2788 */
2789 checkKeyIntent(
2790 Binder.getCallingUid(),
2791 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002792 doNotification(
2793 mAccounts,
2794 account,
2795 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002796 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002797 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002798 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002799 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002800 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002801 }.bind();
2802 } finally {
2803 restoreCallingIdentity(identityToken);
2804 }
Fred Quintana60307342009-03-24 22:48:12 -07002805 }
2806
Carlos Valdivia91979be2015-05-22 14:11:35 -07002807 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2808 MessageDigest digester;
2809 try {
2810 digester = MessageDigest.getInstance("SHA-256");
2811 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2812 callerPkg, PackageManager.GET_SIGNATURES);
2813 for (Signature sig : pkgInfo.signatures) {
2814 digester.update(sig.toByteArray());
2815 }
2816 } catch (NoSuchAlgorithmException x) {
2817 Log.wtf(TAG, "SHA-256 should be available", x);
2818 digester = null;
2819 } catch (NameNotFoundException e) {
2820 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2821 digester = null;
2822 }
2823 return (digester == null) ? null : digester.digest();
2824 }
2825
Dianne Hackborn41203752012-08-31 14:05:51 -07002826 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002827 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002828 int uid = intent.getIntExtra(
2829 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2830 String authTokenType = intent.getStringExtra(
2831 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002832 final String titleAndSubtitle =
2833 mContext.getString(R.string.permission_request_notification_with_subtitle,
2834 account.name);
2835 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002836 String title = titleAndSubtitle;
2837 String subtitle = "";
2838 if (index > 0) {
2839 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002840 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002841 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002842 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002843 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05002844 Notification n =
2845 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
2846 .setSmallIcon(android.R.drawable.stat_sys_warning)
2847 .setWhen(0)
2848 .setColor(contextForUser.getColor(
2849 com.android.internal.R.color.system_notification_accent_color))
2850 .setContentTitle(title)
2851 .setContentText(subtitle)
2852 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2853 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2854 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002855 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002856 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002857 }
2858
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002859 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2860 int uid, AccountAuthenticatorResponse response, String authTokenType,
2861 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002862
2863 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002864
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002865 if (startInNewTask) {
2866 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2867 // Since it was set in Eclair+ we can't change it without breaking apps using
2868 // the intent from a non-Activity context. This is the default behavior.
2869 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2870 }
2871 intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
2872 authTokenType, uid) + (packageName != null ? packageName : "")));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002873 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002874 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2875 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002876 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002877
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002878 return intent;
2879 }
2880
2881 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2882 int uid) {
2883 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002884 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002885 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002886 final Pair<Pair<Account, String>, Integer> key =
2887 new Pair<Pair<Account, String>, Integer>(
2888 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002889 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002890 if (id == null) {
2891 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002892 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002893 }
2894 }
2895 return id;
2896 }
2897
Amith Yamasani04e0d262012-02-14 11:50:53 -08002898 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002899 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002900 synchronized (accounts.signinRequiredNotificationIds) {
2901 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002902 if (id == null) {
2903 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002904 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002905 }
2906 }
2907 return id;
2908 }
2909
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002910 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002911 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002912 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002913 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002914 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002915 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2916 Log.v(TAG, "addAccount: accountType " + accountType
2917 + ", response " + response
2918 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002919 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002920 + ", expectActivityLaunch " + expectActivityLaunch
2921 + ", caller's uid " + Binder.getCallingUid()
2922 + ", pid " + Binder.getCallingPid());
2923 }
Fred Quintana382601f2010-03-25 12:25:10 -07002924 if (response == null) throw new IllegalArgumentException("response is null");
2925 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002926
Amith Yamasani71e6c692013-03-24 17:39:28 -07002927 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002928 final int uid = Binder.getCallingUid();
2929 final int userId = UserHandle.getUserId(uid);
2930 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002931 try {
2932 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2933 "User is not allowed to add an account!");
2934 } catch (RemoteException re) {
2935 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002936 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002937 return;
2938 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002939 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002940 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002941 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2942 "User cannot modify accounts of this type (policy).");
2943 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002944 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002945 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2946 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002947 return;
2948 }
2949
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002950 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002951 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2952 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2953 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2954
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002955 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002956 long identityToken = clearCallingIdentity();
2957 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002958 UserAccounts accounts = getUserAccounts(usrId);
2959 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002960 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2961 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002962 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002963 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002964 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002965 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002966 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07002967 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07002968 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002969 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002970
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002971 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002972 protected String toDebugString(long now) {
2973 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07002974 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002975 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002976 }
2977 }.bind();
2978 } finally {
2979 restoreCallingIdentity(identityToken);
2980 }
Fred Quintana60307342009-03-24 22:48:12 -07002981 }
2982
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002983 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002984 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
2985 final String authTokenType, final String[] requiredFeatures,
2986 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002987 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002988 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002989 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2990 Log.v(TAG, "addAccount: accountType " + accountType
2991 + ", response " + response
2992 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002993 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002994 + ", expectActivityLaunch " + expectActivityLaunch
2995 + ", caller's uid " + Binder.getCallingUid()
2996 + ", pid " + Binder.getCallingPid()
2997 + ", for user id " + userId);
2998 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07002999 Preconditions.checkArgument(response != null, "response cannot be null");
3000 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003001 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003002 if (isCrossUser(callingUid, userId)) {
3003 throw new SecurityException(
3004 String.format(
3005 "User %s trying to add account for %s" ,
3006 UserHandle.getCallingUserId(),
3007 userId));
3008 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003009
3010 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003011 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003012 try {
3013 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3014 "User is not allowed to add an account!");
3015 } catch (RemoteException re) {
3016 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003017 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003018 return;
3019 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003020 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003021 try {
3022 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3023 "User cannot modify accounts of this type (policy).");
3024 } catch (RemoteException re) {
3025 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003026 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3027 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003028 return;
3029 }
3030
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003031 final int pid = Binder.getCallingPid();
3032 final int uid = Binder.getCallingUid();
3033 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3034 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3035 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3036
3037 long identityToken = clearCallingIdentity();
3038 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003039 UserAccounts accounts = getUserAccounts(userId);
3040 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003041 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
3042 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003043 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003044 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07003045 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003046 @Override
3047 public void run() throws RemoteException {
3048 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
3049 options);
3050 }
3051
3052 @Override
3053 protected String toDebugString(long now) {
3054 return super.toDebugString(now) + ", addAccount"
3055 + ", accountType " + accountType
3056 + ", requiredFeatures "
3057 + (requiredFeatures != null
3058 ? TextUtils.join(",", requiredFeatures)
3059 : null);
3060 }
3061 }.bind();
3062 } finally {
3063 restoreCallingIdentity(identityToken);
3064 }
3065 }
3066
Sandra Kwan78812282015-11-04 11:19:47 -08003067 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003068 public void startAddAccountSession(
3069 final IAccountManagerResponse response,
3070 final String accountType,
3071 final String authTokenType,
3072 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003073 final boolean expectActivityLaunch,
3074 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003075 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003076 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3077 Log.v(TAG,
3078 "startAddAccountSession: accountType " + accountType
3079 + ", response " + response
3080 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003081 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003082 + ", expectActivityLaunch " + expectActivityLaunch
3083 + ", caller's uid " + Binder.getCallingUid()
3084 + ", pid " + Binder.getCallingPid());
3085 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003086 Preconditions.checkArgument(response != null, "response cannot be null");
3087 Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Sandra Kwan78812282015-11-04 11:19:47 -08003088
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003089 final int uid = Binder.getCallingUid();
3090 final int userId = UserHandle.getUserId(uid);
3091 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003092 try {
3093 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3094 "User is not allowed to add an account!");
3095 } catch (RemoteException re) {
3096 }
3097 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3098 return;
3099 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003100 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003101 try {
3102 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3103 "User cannot modify accounts of this type (policy).");
3104 } catch (RemoteException re) {
3105 }
3106 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3107 userId);
3108 return;
3109 }
Sandra Kwan78812282015-11-04 11:19:47 -08003110 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003111 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3112 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3113 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3114
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003115 // Check to see if the Password should be included to the caller.
3116 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3117 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003118 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003119
Sandra Kwan78812282015-11-04 11:19:47 -08003120 long identityToken = clearCallingIdentity();
3121 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003122 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003123 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3124 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003125 new StartAccountSession(
3126 accounts,
3127 response,
3128 accountType,
3129 expectActivityLaunch,
3130 null /* accountName */,
3131 false /* authDetailsRequired */,
3132 true /* updateLastAuthenticationTime */,
3133 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003134 @Override
3135 public void run() throws RemoteException {
3136 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3137 requiredFeatures, options);
3138 }
3139
3140 @Override
3141 protected String toDebugString(long now) {
3142 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3143 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3144 + accountType + ", requiredFeatures "
3145 + (requiredFeatures != null ? requiredFeaturesStr : null);
3146 }
3147 }.bind();
3148 } finally {
3149 restoreCallingIdentity(identityToken);
3150 }
3151 }
3152
3153 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3154 private abstract class StartAccountSession extends Session {
3155
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003156 private final boolean mIsPasswordForwardingAllowed;
3157
3158 public StartAccountSession(
3159 UserAccounts accounts,
3160 IAccountManagerResponse response,
3161 String accountType,
3162 boolean expectActivityLaunch,
3163 String accountName,
3164 boolean authDetailsRequired,
3165 boolean updateLastAuthenticationTime,
3166 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003167 super(accounts, response, accountType, expectActivityLaunch,
3168 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3169 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003170 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003171 }
3172
3173 @Override
3174 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003175 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003176 mNumResults++;
3177 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003178 if (result != null
3179 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003180 checkKeyIntent(
3181 Binder.getCallingUid(),
3182 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003183 }
Sandra Kwan78812282015-11-04 11:19:47 -08003184 IAccountManagerResponse response;
3185 if (mExpectActivityLaunch && result != null
3186 && result.containsKey(AccountManager.KEY_INTENT)) {
3187 response = mResponse;
3188 } else {
3189 response = getResponseAndClose();
3190 }
3191 if (response == null) {
3192 return;
3193 }
3194 if (result == null) {
3195 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3196 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3197 + response);
3198 }
3199 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3200 "null bundle returned");
3201 return;
3202 }
3203
3204 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3205 // All AccountManager error codes are greater
3206 // than 0
3207 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3208 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3209 return;
3210 }
3211
Hongming Jin368aa192016-07-29 14:29:54 -07003212 // Omit passwords if the caller isn't permitted to see them.
3213 if (!mIsPasswordForwardingAllowed) {
3214 result.remove(AccountManager.KEY_PASSWORD);
3215 }
3216
Sandra Kwan78812282015-11-04 11:19:47 -08003217 // Strip auth token from result.
3218 result.remove(AccountManager.KEY_AUTHTOKEN);
3219
3220 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3221 Log.v(TAG,
3222 getClass().getSimpleName() + " calling onResult() on response " + response);
3223 }
3224
3225 // Get the session bundle created by authenticator. The
3226 // bundle contains data necessary for finishing the session
3227 // later. The session bundle will be encrypted here and
3228 // decrypted later when trying to finish the session.
3229 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3230 if (sessionBundle != null) {
3231 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3232 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003233 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003234 Log.w(TAG, "Account type in session bundle doesn't match request.");
3235 }
3236 // Add accountType info to session bundle. This will
3237 // override any value set by authenticator.
3238 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3239
3240 // Encrypt session bundle before returning to caller.
3241 try {
3242 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3243 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3244 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3245 } catch (GeneralSecurityException e) {
3246 if (Log.isLoggable(TAG, Log.DEBUG)) {
3247 Log.v(TAG, "Failed to encrypt session bundle!", e);
3248 }
3249 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3250 "failed to encrypt session bundle");
3251 return;
3252 }
3253 }
3254
3255 sendResponse(response, result);
3256 }
3257 }
3258
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003259 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003260 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003261 @NonNull Bundle sessionBundle,
3262 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003263 Bundle appInfo,
3264 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003265 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003266 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003267 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3268 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003269 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003270 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003271 + ", caller's uid " + callingUid
3272 + ", caller's user id " + UserHandle.getCallingUserId()
3273 + ", pid " + Binder.getCallingPid()
3274 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003275 }
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003276 Preconditions.checkArgument(response != null, "response cannot be null");
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003277 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3278 // Account type is added to it before encryption.
3279 if (sessionBundle == null || sessionBundle.size() == 0) {
3280 throw new IllegalArgumentException("sessionBundle is empty");
3281 }
3282
Dmitry Dementyev52745472016-12-02 10:27:45 -08003283 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003284 if (isCrossUser(callingUid, userId)) {
3285 throw new SecurityException(
3286 String.format(
3287 "User %s trying to finish session for %s without cross user permission",
3288 UserHandle.getCallingUserId(),
3289 userId));
3290 }
3291
Sandra Kwan0b84b452016-01-20 15:25:42 -08003292 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003293 sendErrorResponse(response,
3294 AccountManager.ERROR_CODE_USER_RESTRICTED,
3295 "User is not allowed to add an account!");
3296 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3297 return;
3298 }
3299
3300 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003301 final Bundle decryptedBundle;
3302 final String accountType;
3303 // First decrypt session bundle to get account type for checking permission.
3304 try {
3305 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3306 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3307 if (decryptedBundle == null) {
3308 sendErrorResponse(
3309 response,
3310 AccountManager.ERROR_CODE_BAD_REQUEST,
3311 "failed to decrypt session bundle");
3312 return;
3313 }
3314 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3315 // Account type cannot be null. This should not happen if session bundle was created
3316 // properly by #StartAccountSession.
3317 if (TextUtils.isEmpty(accountType)) {
3318 sendErrorResponse(
3319 response,
3320 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3321 "accountType is empty");
3322 return;
3323 }
3324
3325 // If by any chances, decryptedBundle contains colliding keys with
3326 // system info
3327 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3328 // update credentials flow, we should replace with the new values of the current call.
3329 if (appInfo != null) {
3330 decryptedBundle.putAll(appInfo);
3331 }
3332
3333 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003334 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003335 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3336 } catch (GeneralSecurityException e) {
3337 if (Log.isLoggable(TAG, Log.DEBUG)) {
3338 Log.v(TAG, "Failed to decrypt session bundle!", e);
3339 }
3340 sendErrorResponse(
3341 response,
3342 AccountManager.ERROR_CODE_BAD_REQUEST,
3343 "failed to decrypt session bundle");
3344 return;
3345 }
3346
Sandra Kwan0b84b452016-01-20 15:25:42 -08003347 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003348 sendErrorResponse(
3349 response,
3350 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3351 "User cannot modify accounts of this type (policy).");
3352 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3353 userId);
3354 return;
3355 }
3356
3357 long identityToken = clearCallingIdentity();
3358 try {
3359 UserAccounts accounts = getUserAccounts(userId);
3360 logRecordWithUid(
3361 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003362 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3363 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003364 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003365 new Session(
3366 accounts,
3367 response,
3368 accountType,
3369 expectActivityLaunch,
3370 true /* stripAuthTokenFromResult */,
3371 null /* accountName */,
3372 false /* authDetailsRequired */,
3373 true /* updateLastAuthenticationTime */) {
3374 @Override
3375 public void run() throws RemoteException {
3376 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3377 }
3378
3379 @Override
3380 protected String toDebugString(long now) {
3381 return super.toDebugString(now)
3382 + ", finishSession"
3383 + ", accountType " + accountType;
3384 }
3385 }.bind();
3386 } finally {
3387 restoreCallingIdentity(identityToken);
3388 }
3389 }
3390
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003391 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003392 final DevicePolicyManagerInternal dpmi =
3393 LocalServices.getService(DevicePolicyManagerInternal.class);
3394 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003395 if (dpmi == null) {
3396 intent = getDefaultCantAddAccountIntent(errorCode);
3397 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003398 intent = dpmi.createUserRestrictionSupportIntent(userId,
3399 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3400 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3401 intent = dpmi.createShowAdminSupportIntent(userId, false);
3402 }
3403 if (intent == null) {
3404 intent = getDefaultCantAddAccountIntent(errorCode);
3405 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003406 long identityToken = clearCallingIdentity();
3407 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003408 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003409 } finally {
3410 restoreCallingIdentity(identityToken);
3411 }
3412 }
3413
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003414 /**
3415 * Called when we don't know precisely who is preventing us from adding an account.
3416 */
3417 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3418 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3419 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3420 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3421 return cantAddAccount;
3422 }
3423
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003424 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003425 public void confirmCredentialsAsUser(
3426 IAccountManagerResponse response,
3427 final Account account,
3428 final Bundle options,
3429 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003430 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003431 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003432 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003433 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3434 Log.v(TAG, "confirmCredentials: " + account
3435 + ", response " + response
3436 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003437 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003438 + ", pid " + Binder.getCallingPid());
3439 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003440 // Only allow the system process to read accounts of other users
3441 if (isCrossUser(callingUid, userId)) {
3442 throw new SecurityException(
3443 String.format(
3444 "User %s trying to confirm account credentials for %s" ,
3445 UserHandle.getCallingUserId(),
3446 userId));
3447 }
Fred Quintana382601f2010-03-25 12:25:10 -07003448 if (response == null) throw new IllegalArgumentException("response is null");
3449 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003450 long identityToken = clearCallingIdentity();
3451 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003452 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003453 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003454 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003455 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003456 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003457 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003458 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003459 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003460 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003461 protected String toDebugString(long now) {
3462 return super.toDebugString(now) + ", confirmCredentials"
3463 + ", " + account;
3464 }
3465 }.bind();
3466 } finally {
3467 restoreCallingIdentity(identityToken);
3468 }
Fred Quintana60307342009-03-24 22:48:12 -07003469 }
3470
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003471 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003472 public void updateCredentials(IAccountManagerResponse response, final Account account,
3473 final String authTokenType, final boolean expectActivityLaunch,
3474 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003475 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003476 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3477 Log.v(TAG, "updateCredentials: " + account
3478 + ", response " + response
3479 + ", authTokenType " + authTokenType
3480 + ", expectActivityLaunch " + expectActivityLaunch
3481 + ", caller's uid " + Binder.getCallingUid()
3482 + ", pid " + Binder.getCallingPid());
3483 }
Fred Quintana382601f2010-03-25 12:25:10 -07003484 if (response == null) throw new IllegalArgumentException("response is null");
3485 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003486 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003487 long identityToken = clearCallingIdentity();
3488 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003489 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003490 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003491 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003492 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003493 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003494 public void run() throws RemoteException {
3495 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3496 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003497 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003498 protected String toDebugString(long now) {
3499 if (loginOptions != null) loginOptions.keySet();
3500 return super.toDebugString(now) + ", updateCredentials"
3501 + ", " + account
3502 + ", authTokenType " + authTokenType
3503 + ", loginOptions " + loginOptions;
3504 }
3505 }.bind();
3506 } finally {
3507 restoreCallingIdentity(identityToken);
3508 }
Fred Quintana60307342009-03-24 22:48:12 -07003509 }
3510
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003511 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003512 public void startUpdateCredentialsSession(
3513 IAccountManagerResponse response,
3514 final Account account,
3515 final String authTokenType,
3516 final boolean expectActivityLaunch,
3517 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003518 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003519 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3520 Log.v(TAG,
3521 "startUpdateCredentialsSession: " + account + ", response " + response
3522 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3523 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3524 + ", pid " + Binder.getCallingPid());
3525 }
3526 if (response == null) {
3527 throw new IllegalArgumentException("response is null");
3528 }
3529 if (account == null) {
3530 throw new IllegalArgumentException("account is null");
3531 }
Sandra Kwana578d112015-12-16 16:01:43 -08003532
3533 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003534 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003535
3536 // Check to see if the Password should be included to the caller.
3537 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3538 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003539 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003540
Sandra Kwane68c37e2015-11-12 17:11:49 -08003541 long identityToken = clearCallingIdentity();
3542 try {
3543 UserAccounts accounts = getUserAccounts(userId);
3544 new StartAccountSession(
3545 accounts,
3546 response,
3547 account.type,
3548 expectActivityLaunch,
3549 account.name,
3550 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003551 true /* updateLastCredentialTime */,
3552 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003553 @Override
3554 public void run() throws RemoteException {
3555 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3556 loginOptions);
3557 }
3558
3559 @Override
3560 protected String toDebugString(long now) {
3561 if (loginOptions != null)
3562 loginOptions.keySet();
3563 return super.toDebugString(now)
3564 + ", startUpdateCredentialsSession"
3565 + ", " + account
3566 + ", authTokenType " + authTokenType
3567 + ", loginOptions " + loginOptions;
3568 }
3569 }.bind();
3570 } finally {
3571 restoreCallingIdentity(identityToken);
3572 }
3573 }
3574
3575 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003576 public void isCredentialsUpdateSuggested(
3577 IAccountManagerResponse response,
3578 final Account account,
3579 final String statusToken) {
3580 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3581 Log.v(TAG,
3582 "isCredentialsUpdateSuggested: " + account + ", response " + response
3583 + ", caller's uid " + Binder.getCallingUid()
3584 + ", pid " + Binder.getCallingPid());
3585 }
3586 if (response == null) {
3587 throw new IllegalArgumentException("response is null");
3588 }
3589 if (account == null) {
3590 throw new IllegalArgumentException("account is null");
3591 }
3592 if (TextUtils.isEmpty(statusToken)) {
3593 throw new IllegalArgumentException("status token is empty");
3594 }
3595
Sandra Kwan390c9d22016-01-12 14:13:37 -08003596 int usrId = UserHandle.getCallingUserId();
3597 long identityToken = clearCallingIdentity();
3598 try {
3599 UserAccounts accounts = getUserAccounts(usrId);
3600 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3601 false /* stripAuthTokenFromResult */, account.name,
3602 false /* authDetailsRequired */) {
3603 @Override
3604 protected String toDebugString(long now) {
3605 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3606 + ", " + account;
3607 }
3608
3609 @Override
3610 public void run() throws RemoteException {
3611 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3612 }
3613
3614 @Override
3615 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003616 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003617 IAccountManagerResponse response = getResponseAndClose();
3618 if (response == null) {
3619 return;
3620 }
3621
3622 if (result == null) {
3623 sendErrorResponse(
3624 response,
3625 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3626 "null bundle");
3627 return;
3628 }
3629
3630 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3631 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3632 + response);
3633 }
3634 // Check to see if an error occurred. We know if an error occurred because all
3635 // error codes are greater than 0.
3636 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3637 sendErrorResponse(response,
3638 result.getInt(AccountManager.KEY_ERROR_CODE),
3639 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3640 return;
3641 }
3642 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3643 sendErrorResponse(
3644 response,
3645 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3646 "no result in response");
3647 return;
3648 }
3649 final Bundle newResult = new Bundle();
3650 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3651 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3652 sendResponse(response, newResult);
3653 }
3654 }.bind();
3655 } finally {
3656 restoreCallingIdentity(identityToken);
3657 }
3658 }
3659
3660 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003661 public void editProperties(IAccountManagerResponse response, final String accountType,
3662 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003663 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003664 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3665 Log.v(TAG, "editProperties: accountType " + accountType
3666 + ", response " + response
3667 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003668 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003669 + ", pid " + Binder.getCallingPid());
3670 }
Fred Quintana382601f2010-03-25 12:25:10 -07003671 if (response == null) throw new IllegalArgumentException("response is null");
3672 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003673 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003674 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3675 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003676 String msg = String.format(
3677 "uid %s cannot edit authenticator properites for account type: %s",
3678 callingUid,
3679 accountType);
3680 throw new SecurityException(msg);
3681 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003682 long identityToken = clearCallingIdentity();
3683 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003684 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003685 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003686 true /* stripAuthTokenFromResult */, null /* accountName */,
3687 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003688 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003689 public void run() throws RemoteException {
3690 mAuthenticator.editProperties(this, mAccountType);
3691 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003692 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003693 protected String toDebugString(long now) {
3694 return super.toDebugString(now) + ", editProperties"
3695 + ", accountType " + accountType;
3696 }
3697 }.bind();
3698 } finally {
3699 restoreCallingIdentity(identityToken);
3700 }
Fred Quintana60307342009-03-24 22:48:12 -07003701 }
3702
Amith Yamasani12747872015-12-07 14:19:49 -08003703 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003704 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3705 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003706 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003707 throw new SecurityException("Can be called only by system UID");
3708 }
3709 Preconditions.checkNotNull(account, "account cannot be null");
3710 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3711 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3712
3713 final int userId = userHandle.getIdentifier();
3714
3715 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3716
3717 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003718 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003719 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003720 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003721 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003722 return false;
3723 }
3724 }
3725
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003726 // Returns package with oldest target SDK for given UID.
3727 private String getPackageNameForUid(int uid) {
3728 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3729 if (ArrayUtils.isEmpty(packageNames)) {
3730 return null;
3731 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003732 String packageName = packageNames[0];
Fyodor Kupolov892fc8d2017-03-22 12:57:04 -07003733 if (packageNames.length == 1) {
3734 return packageName;
3735 }
3736 // Due to visibility changes we want to use package with oldest target SDK
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003737 int oldestVersion = Integer.MAX_VALUE;
3738 for (String name : packageNames) {
3739 try {
3740 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3741 if (applicationInfo != null) {
3742 int version = applicationInfo.targetSdkVersion;
3743 if (version < oldestVersion) {
3744 oldestVersion = version;
3745 packageName = name;
3746 }
3747 }
3748 } catch (NameNotFoundException e) {
3749 // skip
3750 }
3751 }
3752 return packageName;
3753 }
3754
Svet Ganovf6d424f12016-09-20 20:18:53 -07003755 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3756 int uid) {
3757 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003758 packageName = getPackageNameForUid(uid);
3759 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003760 return false;
3761 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003762 }
3763
3764 // Use null token which means any token. Having a token means the package
3765 // is trusted by the authenticator, hence it is fine to access the account.
3766 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3767 return true;
3768 }
3769 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003770 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003771
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003772 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003773 getUserAccounts(UserHandle.getUserId(uid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003774 return (visibility == AccountManager.VISIBILITY_VISIBLE
Dmitry Dementyev8882d882017-03-14 17:25:46 -07003775 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003776 }
3777
3778 @Override
3779 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3780 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003781 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003782 throw new SecurityException("Can be called only by system UID");
3783 }
3784
3785 Preconditions.checkNotNull(account, "account cannot be null");
3786 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3787 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3788
3789 final int userId = userHandle.getIdentifier();
3790
3791 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3792
3793 final int uid;
3794 try {
3795 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3796 } catch (NameNotFoundException e) {
3797 Slog.e(TAG, "Unknown package " + packageName);
3798 return null;
3799 }
3800
3801 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3802
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003803 final long identity = Binder.clearCallingIdentity();
3804 try {
3805 return PendingIntent.getActivityAsUser(
3806 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3807 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3808 null, new UserHandle(userId)).getIntentSender();
3809 } finally {
3810 Binder.restoreCallingIdentity(identity);
3811 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003812 }
3813
3814 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3815 int uid, RemoteCallback callback) {
3816 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3817 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3818 @Override
3819 public void onResult(Bundle value) throws RemoteException {
3820 handleAuthenticatorResponse(true);
3821 }
3822
3823 @Override
3824 public void onRequestContinued() {
3825 /* ignore */
3826 }
3827
3828 @Override
3829 public void onError(int errorCode, String errorMessage) throws RemoteException {
3830 handleAuthenticatorResponse(false);
3831 }
3832
3833 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3834 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003835 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003836 UserHandle.getUserHandleForUid(uid));
3837 if (callback != null) {
3838 Bundle result = new Bundle();
3839 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3840 callback.sendResult(result);
3841 }
3842 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003843 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003844 }
3845
3846 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003847 public boolean someUserHasAccount(@NonNull final Account account) {
3848 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3849 throw new SecurityException("Only system can check for accounts across users");
3850 }
3851 final long token = Binder.clearCallingIdentity();
3852 try {
3853 AccountAndUser[] allAccounts = getAllAccounts();
3854 for (int i = allAccounts.length - 1; i >= 0; i--) {
3855 if (allAccounts[i].account.equals(account)) {
3856 return true;
3857 }
3858 }
3859 return false;
3860 } finally {
3861 Binder.restoreCallingIdentity(token);
3862 }
3863 }
3864
Fred Quintana33269202009-04-20 16:05:10 -07003865 private class GetAccountsByTypeAndFeatureSession extends Session {
3866 private final String[] mFeatures;
3867 private volatile Account[] mAccountsOfType = null;
3868 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3869 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003870 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003871 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003872
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003873 public GetAccountsByTypeAndFeatureSession(
3874 UserAccounts accounts,
3875 IAccountManagerResponse response,
3876 String type,
3877 String[] features,
3878 int callingUid,
3879 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003880 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003881 true /* stripAuthTokenFromResult */, null /* accountName */,
3882 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003883 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003884 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003885 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003886 }
3887
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003888 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003889 public void run() throws RemoteException {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003890 synchronized (mAccounts.cacheLock) {
Amith Yamasani27db4682013-03-30 17:07:47 -07003891 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003892 mPackageName, false /* include managed not visible*/);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003893 }
Fred Quintana33269202009-04-20 16:05:10 -07003894 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003895 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003896 mCurrentAccount = 0;
3897
3898 checkAccount();
3899 }
3900
3901 public void checkAccount() {
3902 if (mCurrentAccount >= mAccountsOfType.length) {
3903 sendResult();
3904 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003905 }
Fred Quintana33269202009-04-20 16:05:10 -07003906
Fred Quintana29e94b82010-03-10 12:11:51 -08003907 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3908 if (accountAuthenticator == null) {
3909 // It is possible that the authenticator has died, which is indicated by
3910 // mAuthenticator being set to null. If this happens then just abort.
3911 // There is no need to send back a result or error in this case since
3912 // that already happened when mAuthenticator was cleared.
3913 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3914 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3915 + " connected to the authenticator, " + toDebugString());
3916 }
3917 return;
3918 }
Fred Quintana33269202009-04-20 16:05:10 -07003919 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003920 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003921 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003922 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003923 }
3924 }
3925
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003926 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003927 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003928 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003929 mNumResults++;
3930 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003931 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003932 return;
3933 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003934 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003935 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3936 }
3937 mCurrentAccount++;
3938 checkAccount();
3939 }
3940
3941 public void sendResult() {
3942 IAccountManagerResponse response = getResponseAndClose();
3943 if (response != null) {
3944 try {
3945 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3946 for (int i = 0; i < accounts.length; i++) {
3947 accounts[i] = mAccountsWithFeatures.get(i);
3948 }
Fred Quintana56285a62010-12-02 14:20:51 -08003949 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3950 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3951 + response);
3952 }
Fred Quintana33269202009-04-20 16:05:10 -07003953 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003954 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07003955 response.onResult(result);
3956 } catch (RemoteException e) {
3957 // if the caller is dead then there is no one to care about remote exceptions
3958 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3959 Log.v(TAG, "failure while notifying response", e);
3960 }
3961 }
3962 }
3963 }
3964
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003965 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003966 protected String toDebugString(long now) {
3967 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
3968 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
3969 }
3970 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07003971
Amith Yamasani04e0d262012-02-14 11:50:53 -08003972 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003973 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08003974 * @hide
3975 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003976 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07003977 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003978 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003979 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07003980 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
3981 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003982 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08003983 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003984 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003985 long identityToken = clearCallingIdentity();
3986 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003987 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003988 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003989 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003990 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003991 opPackageName,
3992 visibleAccountTypes,
3993 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003994 } finally {
3995 restoreCallingIdentity(identityToken);
3996 }
3997 }
3998
Amith Yamasanif29f2362012-04-05 18:29:52 -07003999 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004000 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004001 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07004002 * @hide
4003 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004004 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004005 public AccountAndUser[] getRunningAccounts() {
4006 final int[] runningUserIds;
4007 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004008 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004009 } catch (RemoteException e) {
4010 // Running in system_server; should never happen
4011 throw new RuntimeException(e);
4012 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004013 return getAccounts(runningUserIds);
4014 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07004015
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004016 /**
4017 * Returns accounts for all users, ignores visibility values.
4018 *
4019 * @hide
4020 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004021 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004022 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07004023 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004024 final int[] userIds = new int[users.size()];
4025 for (int i = 0; i < userIds.length; i++) {
4026 userIds[i] = users.get(i).id;
4027 }
4028 return getAccounts(userIds);
4029 }
4030
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004031 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004032 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004033 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004034 for (int userId : userIds) {
4035 UserAccounts userAccounts = getUserAccounts(userId);
4036 if (userAccounts == null) continue;
4037 synchronized (userAccounts.cacheLock) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004038 Account[] accounts = getAccountsFromCacheLocked(
4039 userAccounts,
4040 null /* type */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004041 Binder.getCallingUid(),
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004042 null /* packageName */,
4043 false /* include managed not visible*/);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07004044 for (int a = 0; a < accounts.length; a++) {
4045 runningAccounts.add(new AccountAndUser(accounts[a], userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07004046 }
4047 }
4048 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004049
4050 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
4051 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07004052 }
4053
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004054 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004055 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004056 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004057 int callingUid = Binder.getCallingUid();
4058 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004059 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004060 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004061 }
4062
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004063 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004064 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004065 String type,
4066 int userId,
4067 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004068 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004069 String opPackageName,
4070 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004071 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004072 // Only allow the system process to read accounts of other users
4073 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004074 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004075 && mContext.checkCallingOrSelfPermission(
4076 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4077 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004078 throw new SecurityException("User " + UserHandle.getCallingUserId()
4079 + " trying to get account for " + userId);
4080 }
4081
Fred Quintana56285a62010-12-02 14:20:51 -08004082 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4083 Log.v(TAG, "getAccounts: accountType " + type
4084 + ", caller's uid " + Binder.getCallingUid()
4085 + ", pid " + Binder.getCallingPid());
4086 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004087
4088 // If the original calling app was using account choosing activity
4089 // provided by the framework or authenticator we'll passing in
4090 // the original caller's uid here, which is what should be used for filtering.
4091 List<String> managedTypes =
4092 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4093 if (packageUid != -1 &&
4094 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4095 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004096 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004097 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004098 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004099 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4100 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004101 if (visibleAccountTypes.isEmpty()
4102 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004103 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004104 } else if (visibleAccountTypes.contains(type)) {
4105 // Prune the list down to just the requested type.
4106 visibleAccountTypes = new ArrayList<>();
4107 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004108 } // else aggregate all the visible accounts (it won't matter if the
4109 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004110
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004111 long identityToken = clearCallingIdentity();
4112 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004113 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004114 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004115 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004116 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004117 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004118 visibleAccountTypes,
4119 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004120 } finally {
4121 restoreCallingIdentity(identityToken);
4122 }
4123 }
4124
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004125 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004126 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004127 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004128 int callingUid,
4129 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004130 List<String> visibleAccountTypes,
4131 boolean includeUserManagedNotVisible) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004132 synchronized (userAccounts.cacheLock) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004133 ArrayList<Account> visibleAccounts = new ArrayList<>();
4134 for (String visibleType : visibleAccountTypes) {
4135 Account[] accountsForType = getAccountsFromCacheLocked(
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004136 userAccounts, visibleType, callingUid, callingPackage,
4137 includeUserManagedNotVisible);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004138 if (accountsForType != null) {
4139 visibleAccounts.addAll(Arrays.asList(accountsForType));
4140 }
4141 }
4142 Account[] result = new Account[visibleAccounts.size()];
4143 for (int i = 0; i < visibleAccounts.size(); i++) {
4144 result[i] = visibleAccounts.get(i);
4145 }
4146 return result;
4147 }
4148 }
4149
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004150 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004151 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4152 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004153 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004154 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004155 for (Account account : accounts) {
4156 addSharedAccountAsUser(account, userId);
4157 }
4158 }
4159
4160 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004161 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004162 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004163 accounts.accountsDb.deleteSharedAccount(account);
4164 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004165 if (accountId < 0) {
4166 Log.w(TAG, "insertAccountIntoDatabase: " + account
4167 + ", skipping the DB insert failed");
4168 return false;
4169 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004170 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4171 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004172 return true;
4173 }
4174
4175 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004176 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4177 userId = handleIncomingUser(userId);
4178 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004179 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4180 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004181 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004182 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004183 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004184 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004185 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004186 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004187 }
4188 return r > 0;
4189 }
4190
4191 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004192 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004193 return removeSharedAccountAsUser(account, userId, getCallingUid());
4194 }
4195
4196 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004197 userId = handleIncomingUser(userId);
4198 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004199 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4200 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004201 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004202 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004203 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004204 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004205 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004206 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004207 }
4208
4209 @Override
4210 public Account[] getSharedAccountsAsUser(int userId) {
4211 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004212 UserAccounts accounts = getUserAccounts(userId);
4213 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004214 Account[] accountArray = new Account[accountList.size()];
4215 accountList.toArray(accountArray);
4216 return accountArray;
4217 }
4218
4219 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004220 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004221 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004222 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004223 }
4224
Amith Yamasani27db4682013-03-30 17:07:47 -07004225 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004226 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004227 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004228 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004229 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004230 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004231 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4232 + callingUid + " with uid=" + uid);
4233 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004234 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004235 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004236 }
4237
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004238 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004239 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004240 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4241 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004242 int callingUid = Binder.getCallingUid();
4243 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004244 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004245 int packageUid = -1;
4246 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004247 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4248 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004249 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004250 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004251 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004252 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004253 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4254 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004255 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004256 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004257 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004258 }
4259
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004260 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004261 public void getAccountsByFeatures(
4262 IAccountManagerResponse response,
4263 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004264 String[] features,
4265 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004266 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004267 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004268 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4269 Log.v(TAG, "getAccounts: accountType " + type
4270 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004271 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004272 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004273 + ", pid " + Binder.getCallingPid());
4274 }
Fred Quintana382601f2010-03-25 12:25:10 -07004275 if (response == null) throw new IllegalArgumentException("response is null");
4276 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004277 int userId = UserHandle.getCallingUserId();
4278
Svetoslavf3f02ac2015-09-08 14:36:35 -07004279 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4280 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004281 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004282 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004283 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004284 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004285 try {
4286 response.onResult(result);
4287 } catch (RemoteException e) {
4288 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4289 }
4290 return;
4291 }
Fred Quintana33269202009-04-20 16:05:10 -07004292 long identityToken = clearCallingIdentity();
4293 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004294 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004295 if (features == null || features.length == 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004296 Account[] accounts;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004297 synchronized (userAccounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004298 accounts = getAccountsFromCacheLocked(
4299 userAccounts, type, callingUid, opPackageName, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004300 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004301 Bundle result = new Bundle();
4302 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4303 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004304 return;
4305 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004306 new GetAccountsByTypeAndFeatureSession(
4307 userAccounts,
4308 response,
4309 type,
4310 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004311 callingUid,
4312 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004313 } finally {
4314 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004315 }
4316 }
4317
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004318 @Override
4319 public void onAccountAccessed(String token) throws RemoteException {
4320 final int uid = Binder.getCallingUid();
4321 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4322 return;
4323 }
4324 final int userId = UserHandle.getCallingUserId();
4325 final long identity = Binder.clearCallingIdentity();
4326 try {
4327 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4328 if (Objects.equals(account.getAccessId(), token)) {
4329 // An app just accessed the account. At this point it knows about
4330 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004331 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004332 if (!hasAccountAccess(account, null, uid)) {
4333 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4334 uid, true);
4335 }
4336 }
4337 }
4338 } finally {
4339 Binder.restoreCallingIdentity(identity);
4340 }
4341 }
4342
Fred Quintanaa698f422009-04-08 19:14:54 -07004343 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004344 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004345 IAccountManagerResponse mResponse;
4346 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004347 final boolean mExpectActivityLaunch;
4348 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004349 final String mAccountName;
4350 // Indicates if we need to add auth details(like last credential time)
4351 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004352 // If set, we need to update the last authenticated time. This is
4353 // currently
4354 // used on
4355 // successful confirming credentials.
4356 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004357
Fred Quintana33269202009-04-20 16:05:10 -07004358 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004359 private int mNumRequestContinued = 0;
4360 private int mNumErrors = 0;
4361
Fred Quintana60307342009-03-24 22:48:12 -07004362 IAccountAuthenticator mAuthenticator = null;
4363
Fred Quintana8570f742010-02-18 10:32:54 -08004364 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004365 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004366
Amith Yamasani04e0d262012-02-14 11:50:53 -08004367 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004368 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4369 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004370 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4371 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4372 }
4373
4374 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4375 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4376 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004377 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004378 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004379 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004380 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004381 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004382 mResponse = response;
4383 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004384 mExpectActivityLaunch = expectActivityLaunch;
4385 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004386 mAccountName = accountName;
4387 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004388 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004389
Fred Quintanaa698f422009-04-08 19:14:54 -07004390 synchronized (mSessions) {
4391 mSessions.put(toString(), this);
4392 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004393 if (response != null) {
4394 try {
4395 response.asBinder().linkToDeath(this, 0 /* flags */);
4396 } catch (RemoteException e) {
4397 mResponse = null;
4398 binderDied();
4399 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004400 }
Fred Quintana60307342009-03-24 22:48:12 -07004401 }
4402
Fred Quintanaa698f422009-04-08 19:14:54 -07004403 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004404 if (mResponse == null) {
4405 // this session has already been closed
4406 return null;
4407 }
Fred Quintana60307342009-03-24 22:48:12 -07004408 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004409 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004410 return response;
4411 }
4412
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004413 /**
4414 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4415 * security policy.
4416 *
4417 * In particular we want to make sure that the Authenticator doesn't try to trick users
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004418 * into launching arbitrary intents on the device via by tricking to click authenticator
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004419 * supplied entries in the system Settings app.
4420 */
4421 protected void checkKeyIntent(
4422 int authUid,
4423 Intent intent) throws SecurityException {
4424 long bid = Binder.clearCallingIdentity();
4425 try {
4426 PackageManager pm = mContext.getPackageManager();
4427 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4428 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4429 int targetUid = targetActivityInfo.applicationInfo.uid;
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004430 if (!isExportedSystemActivity(targetActivityInfo)
4431 && (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4432 targetUid))) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004433 String pkgName = targetActivityInfo.packageName;
4434 String activityName = targetActivityInfo.name;
4435 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4436 + "does not share a signature with the supplying authenticator (%s).";
4437 throw new SecurityException(
4438 String.format(tmpl, activityName, pkgName, mAccountType));
4439 }
4440 } finally {
4441 Binder.restoreCallingIdentity(bid);
4442 }
4443 }
4444
Dmitry Dementyevd5210ba2017-03-14 13:13:35 -07004445 private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
4446 String className = activityInfo.name;
4447 return "android".equals(activityInfo.packageName) &&
4448 (GrantCredentialsPermissionActivity.class.getName().equals(className)
4449 || CantAddAccountActivity.class.getName().equals(className));
4450 }
4451
Fred Quintanaa698f422009-04-08 19:14:54 -07004452 private void close() {
4453 synchronized (mSessions) {
4454 if (mSessions.remove(toString()) == null) {
4455 // the session was already closed, so bail out now
4456 return;
4457 }
4458 }
4459 if (mResponse != null) {
4460 // stop listening for response deaths
4461 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4462
4463 // clear this so that we don't accidentally send any further results
4464 mResponse = null;
4465 }
4466 cancelTimeout();
4467 unbind();
4468 }
4469
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004470 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004471 public void binderDied() {
4472 mResponse = null;
4473 close();
4474 }
4475
4476 protected String toDebugString() {
4477 return toDebugString(SystemClock.elapsedRealtime());
4478 }
4479
4480 protected String toDebugString(long now) {
4481 return "Session: expectLaunch " + mExpectActivityLaunch
4482 + ", connected " + (mAuthenticator != null)
4483 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4484 + "/" + mNumErrors + ")"
4485 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4486 }
4487
Fred Quintana60307342009-03-24 22:48:12 -07004488 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004489 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4490 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4491 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004492 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004493 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004494 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004495 }
4496 }
4497
4498 private void unbind() {
4499 if (mAuthenticator != null) {
4500 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004501 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004502 }
4503 }
4504
Fred Quintana60307342009-03-24 22:48:12 -07004505 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004506 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004507 }
4508
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004509 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004510 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004511 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004512 try {
4513 run();
4514 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004515 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004516 "remote exception");
4517 }
Fred Quintana60307342009-03-24 22:48:12 -07004518 }
4519
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004520 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004521 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004522 mAuthenticator = null;
4523 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004524 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004525 try {
4526 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4527 "disconnected");
4528 } catch (RemoteException e) {
4529 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4530 Log.v(TAG, "Session.onServiceDisconnected: "
4531 + "caught RemoteException while responding", e);
4532 }
4533 }
Fred Quintana60307342009-03-24 22:48:12 -07004534 }
4535 }
4536
Fred Quintanab839afc2009-10-14 15:57:28 -07004537 public abstract void run() throws RemoteException;
4538
Fred Quintana60307342009-03-24 22:48:12 -07004539 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004540 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004541 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004542 try {
4543 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4544 "timeout");
4545 } catch (RemoteException e) {
4546 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4547 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4548 e);
4549 }
4550 }
Fred Quintana60307342009-03-24 22:48:12 -07004551 }
4552 }
4553
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004554 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004555 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004556 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004557 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004558 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004559 if (result != null) {
4560 boolean isSuccessfulConfirmCreds = result.getBoolean(
4561 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004562 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004563 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4564 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004565 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004566 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4567 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004568 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004569 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004570 if (needUpdate || mAuthDetailsRequired) {
4571 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4572 if (needUpdate && accountPresent) {
4573 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4574 }
4575 if (mAuthDetailsRequired) {
4576 long lastAuthenticatedTime = -1;
4577 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004578 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004579 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004580 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004581 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004582 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004583 lastAuthenticatedTime);
4584 }
4585 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004586 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004587 if (result != null
4588 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004589 checkKeyIntent(
4590 Binder.getCallingUid(),
4591 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004592 }
4593 if (result != null
4594 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004595 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4596 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004597 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4598 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004599 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4600 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004601 }
Fred Quintana60307342009-03-24 22:48:12 -07004602 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004603 IAccountManagerResponse response;
4604 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004605 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004606 response = mResponse;
4607 } else {
4608 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004609 }
Fred Quintana60307342009-03-24 22:48:12 -07004610 if (response != null) {
4611 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004612 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004613 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4614 Log.v(TAG, getClass().getSimpleName()
4615 + " calling onError() on response " + response);
4616 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004617 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004618 "null bundle returned");
4619 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004620 if (mStripAuthTokenFromResult) {
4621 result.remove(AccountManager.KEY_AUTHTOKEN);
4622 }
Fred Quintana56285a62010-12-02 14:20:51 -08004623 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4624 Log.v(TAG, getClass().getSimpleName()
4625 + " calling onResult() on response " + response);
4626 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004627 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4628 (intent == null)) {
4629 // All AccountManager error codes are greater than 0
4630 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4631 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4632 } else {
4633 response.onResult(result);
4634 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004635 }
Fred Quintana60307342009-03-24 22:48:12 -07004636 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004637 // if the caller is dead then there is no one to care about remote exceptions
4638 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4639 Log.v(TAG, "failure while notifying response", e);
4640 }
Fred Quintana60307342009-03-24 22:48:12 -07004641 }
4642 }
4643 }
Fred Quintana60307342009-03-24 22:48:12 -07004644
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004645 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004646 public void onRequestContinued() {
4647 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004648 }
4649
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004650 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004651 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004652 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004653 IAccountManagerResponse response = getResponseAndClose();
4654 if (response != null) {
4655 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004656 Log.v(TAG, getClass().getSimpleName()
4657 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004658 }
4659 try {
4660 response.onError(errorCode, errorMessage);
4661 } catch (RemoteException e) {
4662 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4663 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4664 }
4665 }
4666 } else {
4667 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4668 Log.v(TAG, "Session.onError: already closed");
4669 }
Fred Quintana60307342009-03-24 22:48:12 -07004670 }
4671 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004672
4673 /**
4674 * find the component name for the authenticator and initiate a bind
4675 * if no authenticator or the bind fails then return false, otherwise return true
4676 */
4677 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004678 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4679 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4680 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004681 if (authenticatorInfo == null) {
4682 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4683 Log.v(TAG, "there is no authenticator for " + authenticatorType
4684 + ", bailing out");
4685 }
4686 return false;
4687 }
4688
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004689 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004690 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004691 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4692 + " which isn't encryption aware");
4693 return false;
4694 }
4695
Fred Quintanab839afc2009-10-14 15:57:28 -07004696 Intent intent = new Intent();
4697 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4698 intent.setComponent(authenticatorInfo.componentName);
4699 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4700 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4701 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004702 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004703 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004704 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4705 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4706 }
4707 return false;
4708 }
4709
Fred Quintanab839afc2009-10-14 15:57:28 -07004710 return true;
4711 }
Fred Quintana60307342009-03-24 22:48:12 -07004712 }
4713
Svet Ganov5d09c992016-09-07 09:57:41 -07004714 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004715 MessageHandler(Looper looper) {
4716 super(looper);
4717 }
Costin Manolache3348f142009-09-29 18:58:36 -07004718
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004719 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004720 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004721 switch (msg.what) {
4722 case MESSAGE_TIMED_OUT:
4723 Session session = (Session)msg.obj;
4724 session.onTimedOut();
4725 break;
4726
Amith Yamasani5be347b2013-03-31 17:44:31 -07004727 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004728 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004729 break;
4730
Fred Quintana60307342009-03-24 22:48:12 -07004731 default:
4732 throw new IllegalStateException("unhandled message: " + msg.what);
4733 }
4734 }
4735 }
4736
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004737 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004738 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004739 }
4740
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004741 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004742 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004743 }
4744
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004745 /*
4746 * This function receives an opened writable database.
4747 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004748 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004749 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004750 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004751 }
4752
4753 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004754 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004755 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004756 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004757 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004758
4759 class LogRecordTask implements Runnable {
4760 private final String action;
4761 private final String tableName;
4762 private final long accountId;
4763 private final UserAccounts userAccount;
4764 private final int callingUid;
4765 private final long userDebugDbInsertionPoint;
4766
4767 LogRecordTask(final String action,
4768 final String tableName,
4769 final long accountId,
4770 final UserAccounts userAccount,
4771 final int callingUid,
4772 final long userDebugDbInsertionPoint) {
4773 this.action = action;
4774 this.tableName = tableName;
4775 this.accountId = accountId;
4776 this.userAccount = userAccount;
4777 this.callingUid = callingUid;
4778 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4779 }
4780
4781 public void run() {
4782 SQLiteStatement logStatement = userAccount.statementForLogging;
4783 logStatement.bindLong(1, accountId);
4784 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004785 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004786 logStatement.bindLong(4, callingUid);
4787 logStatement.bindString(5, tableName);
4788 logStatement.bindLong(6, userDebugDbInsertionPoint);
4789 logStatement.execute();
4790 logStatement.clearBindings();
4791 }
4792 }
4793
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004794 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4795 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004796 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004797 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004798 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004799 }
4800
4801 /*
4802 * This should only be called once to compile the sql statement for logging
4803 * and to find the insertion point.
4804 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004805 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4806 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4807 .calculateDebugTableInsertionPoint();
4808 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004809 }
4810
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004811 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004812 return asBinder();
4813 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004814
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004815 /**
4816 * Searches array of arguments for the specified string
4817 * @param args array of argument strings
4818 * @param value value to search for
4819 * @return true if the value is contained in the array
4820 */
4821 private static boolean scanArgs(String[] args, String value) {
4822 if (args != null) {
4823 for (String arg : args) {
4824 if (value.equals(arg)) {
4825 return true;
4826 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004827 }
4828 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004829 return false;
4830 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004831
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004832 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004833 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Kenny Root3abd75b2011-09-29 11:00:41 -07004834 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4835 != PackageManager.PERMISSION_GRANTED) {
4836 fout.println("Permission Denial: can't dump AccountsManager from from pid="
4837 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
4838 + " without permission " + android.Manifest.permission.DUMP);
4839 return;
4840 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004841 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004842 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004843
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004844 final List<UserInfo> users = getUserManager().getUsers();
4845 for (UserInfo user : users) {
4846 ipw.println("User " + user + ":");
4847 ipw.increaseIndent();
4848 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4849 ipw.println();
4850 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004851 }
4852 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004853
Amith Yamasani04e0d262012-02-14 11:50:53 -08004854 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4855 String[] args, boolean isCheckinRequest) {
4856 synchronized (userAccounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004857 if (isCheckinRequest) {
4858 // This is a checkin request. *Only* upload the account types and the count of each.
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004859 userAccounts.accountsDb.dumpDeAccountsTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004860 } else {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004861 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004862 Process.SYSTEM_UID, null /* packageName */, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004863 fout.println("Accounts: " + accounts.length);
4864 for (Account account : accounts) {
4865 fout.println(" " + account);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004866 }
Fred Quintana307da1a2010-01-21 14:24:20 -08004867
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004868 // Add debug information.
4869 fout.println();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004870 userAccounts.accountsDb.dumpDebugTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004871 fout.println();
4872 synchronized (mSessions) {
4873 final long now = SystemClock.elapsedRealtime();
4874 fout.println("Active Sessions: " + mSessions.size());
4875 for (Session session : mSessions.values()) {
4876 fout.println(" " + session.toDebugString(now));
4877 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004878 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004879
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004880 fout.println();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004881 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004882 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004883 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004884 }
4885
Amith Yamasani04e0d262012-02-14 11:50:53 -08004886 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004887 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004888 long identityToken = clearCallingIdentity();
4889 try {
4890 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4891 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4892 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004893
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004894 if (intent.getComponent() != null &&
4895 GrantCredentialsPermissionActivity.class.getName().equals(
4896 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004897 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004898 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004899 Context contextForUser = getContextForUser(new UserHandle(userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004900 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07004901 intent.addCategory(String.valueOf(notificationId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004902
Fred Quintana33f889a2009-09-14 17:31:26 -07004903 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004904 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004905 Notification n =
4906 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004907 .setWhen(0)
4908 .setSmallIcon(android.R.drawable.stat_sys_warning)
4909 .setColor(contextForUser.getColor(
4910 com.android.internal.R.color.system_notification_accent_color))
4911 .setContentTitle(String.format(notificationTitleFormat, account.name))
4912 .setContentText(message)
4913 .setContentIntent(PendingIntent.getActivityAsUser(
4914 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004915 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004916 .build();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004917 installNotification(notificationId, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004918 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004919 } finally {
4920 restoreCallingIdentity(identityToken);
4921 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004922 }
4923
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004924 private void installNotification(int notificationId, final Notification notification,
4925 String packageName, int userId) {
4926 final long token = clearCallingIdentity();
4927 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004928 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004929 try {
4930 notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
4931 notificationId, notification, new int[1], userId);
4932 } catch (RemoteException e) {
4933 /* ignore - local call */
4934 }
4935 } finally {
4936 Binder.restoreCallingIdentity(token);
4937 }
Fred Quintana56285a62010-12-02 14:20:51 -08004938 }
4939
Fyodor Kupolovda993802016-09-21 14:47:10 -07004940 private void cancelNotification(int id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004941 cancelNotification(id, mContext.getPackageName(), user);
4942 }
4943
Fyodor Kupolovda993802016-09-21 14:47:10 -07004944 private void cancelNotification(int id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004945 long identityToken = clearCallingIdentity();
4946 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004947 INotificationManager service = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004948 service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
4949 } catch (RemoteException e) {
4950 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004951 } finally {
4952 restoreCallingIdentity(identityToken);
4953 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004954 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004955
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004956 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
4957 final long identity = Binder.clearCallingIdentity();
4958 try {
4959 IPackageManager pm = ActivityThread.getPackageManager();
4960 for (String perm : permissions) {
4961 if (pm.checkPermission(perm, packageName, userId)
4962 == PackageManager.PERMISSION_GRANTED) {
4963 return true;
4964 }
4965 }
4966 } catch (RemoteException e) {
4967 /* ignore - local call */
4968 } finally {
4969 Binder.restoreCallingIdentity(identity);
4970 }
4971 return false;
4972 }
4973
Ian Pedowitz358e51f2016-03-15 17:08:27 +00004974 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
4975 for (String perm : permissions) {
4976 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
4977 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4978 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
4979 }
4980 final int opCode = AppOpsManager.permissionToOpCode(perm);
4981 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
4982 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
4983 return true;
4984 }
4985 }
4986 }
4987 return false;
4988 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004989
Amith Yamasani67df64b2012-12-14 12:09:36 -08004990 private int handleIncomingUser(int userId) {
4991 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004992 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08004993 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
4994 } catch (RemoteException re) {
4995 // Shouldn't happen, local.
4996 }
4997 return userId;
4998 }
4999
Christopher Tateccbf84f2013-05-08 15:25:41 -07005000 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005001 String[] packages;
5002 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005003 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005004 packages = mPackageManager.getPackagesForUid(callingUid);
5005 } finally {
5006 Binder.restoreCallingIdentity(identityToken);
5007 }
5008 if (packages == null) {
5009 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07005010 return false;
5011 }
Fred Quintana7be59642009-08-24 18:29:25 -07005012 for (String name : packages) {
5013 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005014 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08005015 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08005016 && (packageInfo.applicationInfo.privateFlags
5017 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07005018 return true;
5019 }
5020 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005021 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07005022 return false;
5023 }
5024 }
5025 return false;
5026 }
5027
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005028 private boolean permissionIsGranted(
5029 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005030 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
5031 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5032 Log.v(TAG, "Access to " + account + " granted calling uid is system");
5033 }
5034 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005035 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005036
5037 if (isPrivileged(callerUid)) {
5038 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5039 Log.v(TAG, "Access to " + account + " granted calling uid "
5040 + callerUid + " privileged");
5041 }
5042 return true;
5043 }
5044 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
5045 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5046 Log.v(TAG, "Access to " + account + " granted calling uid "
5047 + callerUid + " manages the account");
5048 }
5049 return true;
5050 }
5051 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
5052 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5053 Log.v(TAG, "Access to " + account + " granted calling uid "
5054 + callerUid + " user granted access");
5055 }
5056 return true;
5057 }
5058
5059 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5060 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5061 }
5062
5063 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005064 }
5065
Svetoslavf3f02ac2015-09-08 14:36:35 -07005066 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5067 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005068 if (accountType == null) {
5069 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005070 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005071 return getTypesVisibleToCaller(callingUid, userId,
5072 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005073 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005074 }
5075
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005076 // Method checks visibility for applications targeing API level below {@link
5077 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005078 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005079 private boolean checkGetAccountsPermission(String packageName, int userId) {
5080 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5081 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5082 }
5083
5084 private boolean checkReadContactsPermission(String packageName, int userId) {
5085 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5086 }
5087
5088 /**
5089 * Method checks package uid and signature with Authenticator which manages accountType.
5090 *
5091 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5092 * SIGNATURE_CHECK_MISMATCH otherwise.
5093 */
5094 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5095 if (accountType == null) {
5096 return SIGNATURE_CHECK_MISMATCH;
5097 }
5098
5099 long identityToken = Binder.clearCallingIdentity();
5100 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5101 try {
5102 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5103 } finally {
5104 Binder.restoreCallingIdentity(identityToken);
5105 }
5106 // Check for signature match with Authenticator.
5107 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5108 : serviceInfos) {
5109 if (accountType.equals(serviceInfo.type.type)) {
5110 if (serviceInfo.uid == callingUid) {
5111 return SIGNATURE_CHECK_UID_MATCH;
5112 }
5113 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5114 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5115 return SIGNATURE_CHECK_MATCH;
5116 }
5117 }
5118 }
5119 return SIGNATURE_CHECK_MISMATCH;
5120 }
5121
5122 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005123 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5124 if (accountType == null) {
5125 return false;
5126 } else {
5127 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5128 }
5129 }
5130
Svetoslavf3f02ac2015-09-08 14:36:35 -07005131 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5132 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005133 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005134 }
5135
5136 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005137 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005138 }
5139
5140 private List<String> getTypesForCaller(
5141 int callingUid, int userId, boolean isOtherwisePermitted) {
5142 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005143 long identityToken = Binder.clearCallingIdentity();
5144 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5145 try {
5146 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5147 } finally {
5148 Binder.restoreCallingIdentity(identityToken);
5149 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005150 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005151 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005152 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5153 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005154 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005155 }
5156 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005157 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005158 }
5159
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005160 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5161 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5162 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5163 if (account.name.equals(accountName)) {
5164 return true;
5165 }
5166 }
5167 }
5168 return false;
5169 }
5170
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005171 private static void checkManageUsersPermission(String message) {
5172 if (ActivityManager.checkComponentPermission(
5173 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5174 != PackageManager.PERMISSION_GRANTED) {
5175 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5176 }
5177 }
5178
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005179 private static void checkManageOrCreateUsersPermission(String message) {
5180 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5181 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5182 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5183 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5184 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5185 + message);
5186 }
5187 }
5188
Amith Yamasani04e0d262012-02-14 11:50:53 -08005189 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5190 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005191 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005192 return true;
5193 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005194 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005195 synchronized (accounts.cacheLock) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005196 long grantsCount;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005197 if (authTokenType != null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005198 grantsCount = accounts.accountsDb.findMatchingGrantsCount(callerUid, authTokenType,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005199 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005200 } else {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005201 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005202 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005203 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005204 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005205
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005206 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5207 // TODO: Skip this check when running automated tests. Replace this
5208 // with a more general solution.
5209 Log.d(TAG, "no credentials permission for usage of " + account + ", "
Amith Yamasani04e0d262012-02-14 11:50:53 -08005210 + authTokenType + " by uid " + callerUid
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005211 + " but ignoring since device is in test harness.");
5212 return true;
5213 }
5214 return permissionGranted;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005215 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005216 }
5217
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005218 private boolean isSystemUid(int callingUid) {
5219 String[] packages = null;
5220 long ident = Binder.clearCallingIdentity();
5221 try {
5222 packages = mPackageManager.getPackagesForUid(callingUid);
5223 } finally {
5224 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005225 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005226 if (packages != null) {
5227 for (String name : packages) {
5228 try {
5229 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5230 if (packageInfo != null
5231 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5232 != 0) {
5233 return true;
5234 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005235 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005236 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5237 }
5238 }
5239 } else {
5240 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005241 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005242 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005243 }
5244
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005245 /** Succeeds if any of the specified permissions are granted. */
5246 private void checkReadAccountsPermitted(
5247 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005248 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005249 int userId,
5250 String opPackageName) {
5251 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005252 String msg = String.format(
5253 "caller uid %s cannot access %s accounts",
5254 callingUid,
5255 accountType);
5256 Log.w(TAG, " " + msg);
5257 throw new SecurityException(msg);
5258 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005259 }
5260
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005261 private boolean canUserModifyAccounts(int userId, int callingUid) {
5262 // the managing app can always modify accounts
5263 if (isProfileOwner(callingUid)) {
5264 return true;
5265 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005266 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5267 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5268 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005269 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005270 return true;
5271 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005272
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005273 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5274 // the managing app can always modify accounts
5275 if (isProfileOwner(callingUid)) {
5276 return true;
5277 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005278 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5279 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005280 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005281 if (typesArray == null) {
5282 return true;
5283 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005284 for (String forbiddenType : typesArray) {
5285 if (forbiddenType.equals(accountType)) {
5286 return false;
5287 }
5288 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005289 return true;
5290 }
5291
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005292 private boolean isProfileOwner(int uid) {
5293 final DevicePolicyManagerInternal dpmi =
5294 LocalServices.getService(DevicePolicyManagerInternal.class);
5295 return (dpmi != null)
5296 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5297 }
5298
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005299 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005300 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5301 throws RemoteException {
5302 final int callingUid = getCallingUid();
5303
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005304 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005305 throw new SecurityException();
5306 }
5307
5308 if (value) {
5309 grantAppPermission(account, authTokenType, uid);
5310 } else {
5311 revokeAppPermission(account, authTokenType, uid);
5312 }
5313 }
5314
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005315 /**
5316 * Allow callers with the given uid permission to get credentials for 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 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005322 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005323 if (account == null || authTokenType == null) {
5324 Log.e(TAG, "grantAppPermission: 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 long accountId = accounts.accountsDb.findDeAccountId(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005330 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005331 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005332 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005333 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005334 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005335
5336 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005337 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005338
5339 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5340 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5341 : mAppPermissionChangeListeners) {
5342 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5343 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005344 }
5345
5346 /**
5347 * Don't allow callers with the given uid permission to get credentials for
5348 * account/authTokenType.
5349 * <p>
5350 * Although this is public it can only be accessed via the AccountManagerService object
5351 * which is in the system. This means we don't need to protect it with permissions.
5352 * @hide
5353 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005354 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005355 if (account == null || authTokenType == null) {
5356 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005357 return;
5358 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005359 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005360 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005361 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005362 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005363 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005364 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005365 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5366 accountId, authTokenType, uid);
5367 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005368 }
5369 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005370 accounts.accountsDb.endTransaction();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005371 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005372
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005373 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
5374 new UserHandle(accounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005375 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005376
5377 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5378 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5379 : mAppPermissionChangeListeners) {
5380 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5381 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005382 }
Fred Quintana56285a62010-12-02 14:20:51 -08005383
Amith Yamasani04e0d262012-02-14 11:50:53 -08005384 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5385 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005386 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005387 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005388 for (Account curAccount : oldAccountsForType) {
5389 if (!curAccount.equals(account)) {
5390 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005391 }
5392 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005393 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005394 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005395 } else {
5396 Account[] newAccountsForType = new Account[newAccountsList.size()];
5397 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005398 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005399 }
Fred Quintana56285a62010-12-02 14:20:51 -08005400 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005401 accounts.userDataCache.remove(account);
5402 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005403 accounts.previousNameCache.remove(account);
Dmitry Dementyev71fa5262017-03-23 12:29:17 -07005404 accounts.visibilityCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005405 }
5406
5407 /**
5408 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005409 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5410 * processes and if you will return this account to apps you should return the result.
5411 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005412 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005413 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005414 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005415 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5416 Account[] newAccountsForType = new Account[oldLength + 1];
5417 if (accountsForType != null) {
5418 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005419 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005420 String token = account.getAccessId() != null ? account.getAccessId()
5421 : UUID.randomUUID().toString();
5422 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005423 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005424 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005425 }
5426
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005427 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005428 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005429 @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005430 String visibilityFilterPackage = callingPackage;
5431 if (visibilityFilterPackage == null) {
5432 visibilityFilterPackage = getPackageNameForUid(callingUid);
5433 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005434 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005435 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005436 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005437 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5438 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5439 || (includeManagedNotVisible
5440 && (visibility
5441 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5442 firstPass.put(account, visibility);
5443 }
5444 }
5445 Map<Account, Integer> secondPass =
5446 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5447
5448 Account[] filtered = new Account[secondPass.size()];
5449 filtered = secondPass.keySet().toArray(filtered);
5450 return filtered;
5451 }
5452
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005453 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005454 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005455 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005456 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005457 // first part is to filter shared accounts.
5458 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005459 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005460 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005461 return unfiltered;
5462 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005463 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005464 if (user != null && user.isRestricted()) {
Dmitry Dementyev16e37892017-03-22 13:13:40 -07005465 String[] packages = mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005466 if (packages == null) {
5467 packages = new String[] {};
5468 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005469 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005470 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005471 // This might be a temporary way to specify a visible list
5472 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005473 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5474 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005475 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005476 return unfiltered;
5477 }
5478 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005479 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005480 if (ArrayUtils.isEmpty(sharedAccounts)) {
5481 return unfiltered;
5482 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005483 String requiredAccountType = "";
5484 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005485 // If there's an explicit callingPackage specified, check if that package
5486 // opted in to see restricted accounts.
5487 if (callingPackage != null) {
5488 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005489 if (pi != null && pi.restrictedAccountType != null) {
5490 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005491 }
5492 } else {
5493 // Otherwise check if the callingUid has a package that has opted in
5494 for (String packageName : packages) {
5495 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5496 if (pi != null && pi.restrictedAccountType != null) {
5497 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005498 break;
5499 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005500 }
5501 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005502 } catch (NameNotFoundException e) {
5503 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005504 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005505 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005506 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5507 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005508 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005509 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005510 } else {
5511 boolean found = false;
5512 for (Account shared : sharedAccounts) {
5513 if (shared.equals(account)) {
5514 found = true;
5515 break;
5516 }
5517 }
5518 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005519 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005520 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005521 }
5522 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005523 return filtered;
5524 } else {
5525 return unfiltered;
5526 }
5527 }
5528
Amith Yamasani27db4682013-03-30 17:07:47 -07005529 /*
5530 * packageName can be null. If not null, it should be used to filter out restricted accounts
5531 * that the package is not allowed to access.
5532 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005533 @NonNull
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005534 protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005535 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005536 if (accountType != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005537 final Account[] accounts = userAccounts.accountCache.get(accountType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005538 if (accounts == null) {
5539 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005540 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005541 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5542 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005543 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005544 } else {
5545 int totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005546 for (Account[] accounts : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005547 totalLength += accounts.length;
5548 }
5549 if (totalLength == 0) {
5550 return EMPTY_ACCOUNT_ARRAY;
5551 }
5552 Account[] accounts = new Account[totalLength];
5553 totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005554 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005555 System.arraycopy(accountsOfType, 0, accounts, totalLength,
5556 accountsOfType.length);
5557 totalLength += accountsOfType.length;
5558 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005559 return filterAccounts(userAccounts, accounts, callingUid, callingPackage,
5560 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005561 }
5562 }
5563
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005564 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005565 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005566 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005567 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005568 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005569 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005570 }
5571 if (value == null) {
5572 userDataForAccount.remove(key);
5573 } else {
5574 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005575 }
5576 }
5577
Carlos Valdivia91979be2015-05-22 14:11:35 -07005578 protected String readCachedTokenInternal(
5579 UserAccounts accounts,
5580 Account account,
5581 String tokenType,
5582 String callingPackage,
5583 byte[] pkgSigDigest) {
5584 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005585 return accounts.accountTokenCaches.get(
5586 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07005587 }
5588 }
5589
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005590 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005591 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005592 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005593 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005594 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005595 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005596 }
5597 if (value == null) {
5598 authTokensForAccount.remove(key);
5599 } else {
5600 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005601 }
5602 }
5603
Amith Yamasani04e0d262012-02-14 11:50:53 -08005604 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5605 String authTokenType) {
5606 synchronized (accounts.cacheLock) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005607 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005608 if (authTokensForAccount == null) {
5609 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005610 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005611 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005612 }
5613 return authTokensForAccount.get(authTokenType);
5614 }
5615 }
5616
Simranjit Kohli858511c2016-03-10 18:36:11 +00005617 protected String readUserDataInternalLocked(
5618 UserAccounts accounts, Account account, String key) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005619 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005620 if (userDataForAccount == null) {
5621 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005622 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005623 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005624 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005625 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005626 }
5627
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005628 private Context getContextForUser(UserHandle user) {
5629 try {
5630 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5631 } catch (NameNotFoundException e) {
5632 // Default to mContext, not finding the package system is running as is unlikely.
5633 return mContext;
5634 }
5635 }
Sandra Kwan78812282015-11-04 11:19:47 -08005636
5637 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5638 try {
5639 response.onResult(result);
5640 } catch (RemoteException e) {
5641 // if the caller is dead then there is no one to care about remote
5642 // exceptions
5643 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5644 Log.v(TAG, "failure while notifying response", e);
5645 }
5646 }
5647 }
5648
5649 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5650 String errorMessage) {
5651 try {
5652 response.onError(errorCode, errorMessage);
5653 } catch (RemoteException e) {
5654 // if the caller is dead then there is no one to care about remote
5655 // exceptions
5656 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5657 Log.v(TAG, "failure while notifying response", e);
5658 }
5659 }
5660 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005661
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005662 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005663 private final Object mLock = new Object();
5664
5665 @GuardedBy("mLock")
5666 private AccountManagerBackupHelper mBackupHelper;
5667
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005668 @Override
5669 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5670 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5671 if (account == null) {
5672 Slog.w(TAG, "account cannot be null");
5673 return;
5674 }
5675 if (packageName == null) {
5676 Slog.w(TAG, "packageName cannot be null");
5677 return;
5678 }
5679 if (userId < UserHandle.USER_SYSTEM) {
5680 Slog.w(TAG, "user id must be concrete");
5681 return;
5682 }
5683 if (callback == null) {
5684 Slog.w(TAG, "callback cannot be null");
5685 return;
5686 }
5687
Svet Ganovf6d424f12016-09-20 20:18:53 -07005688 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5689 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005690 Bundle result = new Bundle();
5691 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5692 callback.sendResult(result);
5693 return;
5694 }
5695
5696 final int uid;
5697 try {
5698 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5699 } catch (NameNotFoundException e) {
5700 Slog.e(TAG, "Unknown package " + packageName);
5701 return;
5702 }
5703
5704 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005705 final UserAccounts userAccounts;
5706 synchronized (mUsers) {
5707 userAccounts = mUsers.get(userId);
5708 }
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04005709 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005710 doNotification(userAccounts, account, null, intent, packageName, userId);
5711 }
5712
5713 @Override
5714 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5715 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5716 mAppPermissionChangeListeners.add(listener);
5717 }
5718
5719 @Override
5720 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5721 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005722 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005723
5724 @Override
5725 public byte[] backupAccountAccessPermissions(int userId) {
5726 synchronized (mLock) {
5727 if (mBackupHelper == null) {
5728 mBackupHelper = new AccountManagerBackupHelper(
5729 AccountManagerService.this, this);
5730 }
5731 return mBackupHelper.backupAccountAccessPermissions(userId);
5732 }
5733 }
5734
5735 @Override
5736 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5737 synchronized (mLock) {
5738 if (mBackupHelper == null) {
5739 mBackupHelper = new AccountManagerBackupHelper(
5740 AccountManagerService.this, this);
5741 }
5742 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5743 }
5744 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005745 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005746
5747 @VisibleForTesting
5748 static class Injector {
5749 private final Context mContext;
5750
5751 public Injector(Context context) {
5752 mContext = context;
5753 }
5754
5755 Looper getMessageHandlerLooper() {
5756 ServiceThread serviceThread = new ServiceThread(TAG,
5757 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5758 serviceThread.start();
5759 return serviceThread.getLooper();
5760 }
5761
5762 Context getContext() {
5763 return mContext;
5764 }
5765
5766 void addLocalService(AccountManagerInternal service) {
5767 LocalServices.addService(AccountManagerInternal.class, service);
5768 }
5769
5770 String getDeDatabaseName(int userId) {
5771 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5772 AccountsDb.DE_DATABASE_NAME);
5773 return databaseFile.getPath();
5774 }
5775
5776 String getCeDatabaseName(int userId) {
5777 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5778 AccountsDb.CE_DATABASE_NAME);
5779 return databaseFile.getPath();
5780 }
5781
5782 String getPreNDatabaseName(int userId) {
5783 File systemDir = Environment.getDataSystemDirectory();
5784 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5785 PRE_N_DATABASE_NAME);
5786 if (userId == 0) {
5787 // Migrate old file, if it exists, to the new location.
5788 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005789 // accidentally created in the old location,
5790 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005791 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5792 if (oldFile.exists() && !databaseFile.exists()) {
5793 // Check for use directory; create if it doesn't exist, else renameTo will fail
5794 File userDir = Environment.getUserSystemDirectory(userId);
5795 if (!userDir.exists()) {
5796 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005797 throw new IllegalStateException(
5798 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005799 }
5800 }
5801 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005802 throw new IllegalStateException(
5803 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005804 }
5805 }
5806 }
5807 return databaseFile.getPath();
5808 }
5809
5810 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5811 return new AccountAuthenticatorCache(mContext);
5812 }
5813
5814 INotificationManager getNotificationManager() {
5815 return NotificationManager.getService();
5816 }
5817 }
Fred Quintana60307342009-03-24 22:48:12 -07005818}