blob: 5b480d0b7430b4e7718125027aea286486ded9a1 [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;
Amith Yamasani3b458ad2013-04-18 18:40:07 -070038import android.app.AppGlobals;
Svetoslavf3f02ac2015-09-08 14:36:35 -070039import android.app.AppOpsManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070040import android.app.INotificationManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070041import android.app.Notification;
42import android.app.NotificationManager;
43import android.app.PendingIntent;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000044import android.app.admin.DeviceAdminInfo;
Sander Alewijnseda1350f2014-05-08 16:59:42 +010045import android.app.admin.DevicePolicyManager;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000046import android.app.admin.DevicePolicyManagerInternal;
Fred Quintanaa698f422009-04-08 19:14:54 -070047import android.content.BroadcastReceiver;
Doug Zongker885cfc232009-10-21 16:52:44 -070048import android.content.ComponentName;
Fred Quintanaa698f422009-04-08 19:14:54 -070049import android.content.Context;
50import android.content.Intent;
51import android.content.IntentFilter;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070052import android.content.IntentSender;
Fred Quintanab839afc2009-10-14 15:57:28 -070053import android.content.ServiceConnection;
Carlos Valdivia6ede9c32016-03-10 20:12:32 -080054import android.content.pm.ActivityInfo;
Doug Zongker885cfc232009-10-21 16:52:44 -070055import android.content.pm.ApplicationInfo;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070056import android.content.pm.IPackageManager;
Doug Zongker885cfc232009-10-21 16:52:44 -070057import android.content.pm.PackageInfo;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070058import android.content.pm.PackageManager;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070059import android.content.pm.PackageManager.NameNotFoundException;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070060import android.content.pm.RegisteredServicesCache;
Fred Quintana3ecd5f42009-09-17 12:42:35 -070061import android.content.pm.RegisteredServicesCacheListener;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -070062import android.content.pm.ResolveInfo;
Carlos Valdivia91979be2015-05-22 14:11:35 -070063import android.content.pm.Signature;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070064import android.content.pm.UserInfo;
Fred Quintana60307342009-03-24 22:48:12 -070065import android.database.Cursor;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -070066import android.database.sqlite.SQLiteStatement;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080067import android.net.Uri;
Doug Zongker885cfc232009-10-21 16:52:44 -070068import android.os.Binder;
Fred Quintanaa698f422009-04-08 19:14:54 -070069import android.os.Bundle;
Oscar Montemayora8529f62009-11-18 10:14:20 -080070import android.os.Environment;
Fred Quintanaa698f422009-04-08 19:14:54 -070071import android.os.Handler;
Fred Quintanaa698f422009-04-08 19:14:54 -070072import android.os.IBinder;
73import android.os.Looper;
74import android.os.Message;
Dianne Hackborn164371f2013-10-01 19:10:13 -070075import android.os.Parcel;
Amith Yamasani27db4682013-03-30 17:07:47 -070076import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070077import android.os.RemoteCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -070078import android.os.RemoteException;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -080079import android.os.StrictMode;
Fred Quintanaa698f422009-04-08 19:14:54 -070080import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070081import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070082import android.os.UserManager;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070083import android.os.storage.StorageManager;
Fred Quintanaa698f422009-04-08 19:14:54 -070084import android.text.TextUtils;
85import android.util.Log;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070086import android.util.Pair;
Jeff Sharkey6eb96202012-10-10 13:13:54 -070087import android.util.Slog;
Amith Yamasani04e0d262012-02-14 11:50:53 -080088import android.util.SparseArray;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -070089import android.util.SparseBooleanArray;
Fred Quintana60307342009-03-24 22:48:12 -070090
Costin Manolacheb61e8fb2011-09-08 11:26:09 -070091import com.android.internal.R;
Svet Ganov5d09c992016-09-07 09:57:41 -070092import com.android.internal.annotations.GuardedBy;
Fyodor Kupoloveeca6582016-04-08 12:14:04 -070093import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070094import com.android.internal.content.PackageMonitor;
Amith Yamasani67df64b2012-12-14 12:09:36 -080095import com.android.internal.util.ArrayUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080096import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -070097import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000098import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -070099import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600100import com.android.server.SystemService;
101
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700102import com.google.android.collect.Lists;
103import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700104
Oscar Montemayora8529f62009-11-18 10:14:20 -0800105import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700106import java.io.FileDescriptor;
107import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800108import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700109import java.security.MessageDigest;
110import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700111import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700112import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800113import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700114import java.util.Collection;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800115import java.util.Collections;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700116import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700117import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700118import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800119import java.util.LinkedHashMap;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800120import java.util.LinkedHashSet;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700121import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800122import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800123import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700124import java.util.Objects;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700125import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700126import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700127import java.util.concurrent.atomic.AtomicInteger;
128import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700129
Fred Quintana60307342009-03-24 22:48:12 -0700130/**
131 * A system service that provides account, password, and authtoken management for all
132 * accounts on the device. Some of these calls are implemented with the help of the corresponding
133 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
134 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700135 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700136 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700137 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700138public class AccountManagerService
139 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800140 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700141 private static final String TAG = "AccountManagerService";
142
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600143 public static class Lifecycle extends SystemService {
144 private AccountManagerService mService;
145
146 public Lifecycle(Context context) {
147 super(context);
148 }
149
150 @Override
151 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700152 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600153 publishBinderService(Context.ACCOUNT_SERVICE, mService);
154 }
155
156 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600157 public void onUnlockUser(int userHandle) {
158 mService.onUnlockUser(userHandle);
159 }
160 }
161
Svet Ganov5d09c992016-09-07 09:57:41 -0700162 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700163
Fred Quintana56285a62010-12-02 14:20:51 -0800164 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700165 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700166 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700167 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800168
Svet Ganov5d09c992016-09-07 09:57:41 -0700169 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700170
Fred Quintana60307342009-03-24 22:48:12 -0700171 // Messages that can be sent on mHandler
172 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700173 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700174
Fred Quintana56285a62010-12-02 14:20:51 -0800175 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700176 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700177 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800178
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800179 private static final int SIGNATURE_CHECK_MISMATCH = 0;
180 private static final int SIGNATURE_CHECK_MATCH = 1;
181 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
182
Carlos Valdivia91979be2015-05-22 14:11:35 -0700183 static {
184 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
185 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
186 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700187
188 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700189 private final AtomicInteger mNotificationIds = new AtomicInteger(1);
190
Amith Yamasani04e0d262012-02-14 11:50:53 -0800191 static class UserAccounts {
192 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700193 final AccountsDb accountsDb;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800194 private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
195 credentialsPermissionNotificationIds =
196 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
197 private final HashMap<Account, Integer> signinRequiredNotificationIds =
198 new HashMap<Account, Integer>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700199 final Object cacheLock = new Object();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800200 /** protected by the {@link #cacheLock} */
Svet Ganov5d09c992016-09-07 09:57:41 -0700201 final HashMap<String, Account[]> accountCache =
Svet Ganovf6d424f12016-09-20 20:18:53 -0700202 new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800203 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700204 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800205 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700206 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700207 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700208 private final TokenCache accountTokenCaches = new TokenCache();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700209
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800210 /** protected by the {@link #cacheLock} */
211 // TODO use callback to set up the map.
212 private final Map<String, LinkedHashSet<String>> mApplicationAccountRequestMappings =
213 new HashMap<>();
214
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700215 /**
216 * protected by the {@link #cacheLock}
217 *
218 * Caches the previous names associated with an account. Previous names
219 * should be cached because we expect that when an Account is renamed,
220 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
221 * want to know if the accounts they care about have been renamed.
222 *
223 * The previous names are wrapped in an {@link AtomicReference} so that
224 * we can distinguish between those accounts with no previous names and
225 * those whose previous names haven't been cached (yet).
226 */
227 private final HashMap<Account, AtomicReference<String>> previousNameCache =
228 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800229
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700230 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700231 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700232
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700233 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800234 this.userId = userId;
235 synchronized (cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700236 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800237 }
238 }
239 }
240
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700241 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600242 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700243 // Not thread-safe. Only use in synchronized context
244 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700245 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
246 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800247
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700248 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700249 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700250
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700251 /**
252 * This should only be called by system code. One should only call this after the service
253 * has started.
254 * @return a reference to the AccountManagerService instance
255 * @hide
256 */
257 public static AccountManagerService getSingleton() {
258 return sThis.get();
259 }
Fred Quintana60307342009-03-24 22:48:12 -0700260
Fyodor Kupolovda993802016-09-21 14:47:10 -0700261 public AccountManagerService(Injector injector) {
262 mInjector = injector;
263 mContext = injector.getContext();
264 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700265 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700266 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
267 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800268 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700269
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700270 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800271
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800272 IntentFilter intentFilter = new IntentFilter();
273 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
274 intentFilter.addDataScheme("package");
275 mContext.registerReceiver(new BroadcastReceiver() {
276 @Override
277 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700278 // Don't delete accounts when updating a authenticator's
279 // package.
280 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700281 /* Purging data requires file io, don't block the main thread. This is probably
282 * less than ideal because we are introducing a race condition where old grants
283 * could be exercised until they are purged. But that race condition existed
284 * anyway with the broadcast receiver.
285 *
286 * Ideally, we would completely clear the cache, purge data from the database,
287 * and then rebuild the cache. All under the cache lock. But that change is too
288 * large at this point.
289 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800290 final String removedPackageName = intent.getData().toString();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700291 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700292 @Override
293 public void run() {
294 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800295 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800296 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700297 }
298 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700299 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700300 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800301 }
302 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800303
Amith Yamasani13593602012-03-22 16:16:17 -0700304 IntentFilter userFilter = new IntentFilter();
305 userFilter.addAction(Intent.ACTION_USER_REMOVED);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800306 mContext.registerReceiverAsUser(new BroadcastReceiver() {
Amith Yamasani13593602012-03-22 16:16:17 -0700307 @Override
308 public void onReceive(Context context, Intent intent) {
Amith Yamasani67df64b2012-12-14 12:09:36 -0800309 String action = intent.getAction();
310 if (Intent.ACTION_USER_REMOVED.equals(action)) {
311 onUserRemoved(intent);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800312 }
Amith Yamasani13593602012-03-22 16:16:17 -0700313 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800314 }, UserHandle.ALL, userFilter, null, null);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700315
Fyodor Kupolovda993802016-09-21 14:47:10 -0700316 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700317
318 // Need to cancel account request notifications if the update/install can access the account
319 new PackageMonitor() {
320 @Override
321 public void onPackageAdded(String packageName, int uid) {
322 // Called on a handler, and running as the system
323 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
324 }
325
326 @Override
327 public void onPackageUpdateFinished(String packageName, int uid) {
328 // Called on a handler, and running as the system
329 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
330 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700331 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700332
333 // Cancel account request notification if an app op was preventing the account access
334 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
335 new AppOpsManager.OnOpChangedInternalListener() {
336 @Override
337 public void onOpChanged(int op, String packageName) {
338 try {
339 final int userId = ActivityManager.getCurrentUser();
340 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
341 final int mode = mAppOpsManager.checkOpNoThrow(
342 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
343 if (mode == AppOpsManager.MODE_ALLOWED) {
344 final long identity = Binder.clearCallingIdentity();
345 try {
346 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
347 } finally {
348 Binder.restoreCallingIdentity(identity);
349 }
350 }
351 } catch (NameNotFoundException e) {
352 /* ignore */
353 }
354 }
355 });
356
357 // Cancel account request notification if a permission was preventing the account access
358 mPackageManager.addOnPermissionsChangeListener(
359 (int uid) -> {
360 Account[] accounts = null;
361 String[] packageNames = mPackageManager.getPackagesForUid(uid);
362 if (packageNames != null) {
363 final int userId = UserHandle.getUserId(uid);
364 final long identity = Binder.clearCallingIdentity();
365 try {
366 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800367 // if app asked for permission we need to cancel notification even
368 // for O+ applications.
369 if (mPackageManager.checkPermission(
370 Manifest.permission.GET_ACCOUNTS,
371 packageName) != PackageManager.PERMISSION_GRANTED) {
372 continue;
373 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700374
375 if (accounts == null) {
376 accounts = getAccountsAsUser(null, userId, "android");
377 if (ArrayUtils.isEmpty(accounts)) {
378 return;
379 }
380 }
381
382 for (Account account : accounts) {
383 cancelAccountAccessRequestNotificationIfNeeded(
384 account, uid, packageName, true);
385 }
386 }
387 } finally {
388 Binder.restoreCallingIdentity(identity);
389 }
390 }
391 });
392 }
393
394 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
395 boolean checkAccess) {
396 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
397 for (Account account : accounts) {
398 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
399 }
400 }
401
402 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
403 boolean checkAccess) {
404 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
405 for (Account account : accounts) {
406 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
407 }
408 }
409
410 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
411 boolean checkAccess) {
412 String[] packageNames = mPackageManager.getPackagesForUid(uid);
413 if (packageNames != null) {
414 for (String packageName : packageNames) {
415 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
416 packageName, checkAccess);
417 }
418 }
419 }
420
421 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
422 int uid, String packageName, boolean checkAccess) {
423 if (!checkAccess || hasAccountAccess(account, packageName,
424 UserHandle.getUserHandleForUid(uid))) {
425 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700426 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700427 UserHandle.getUserHandleForUid(uid));
428 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800429 }
430
Dianne Hackborn164371f2013-10-01 19:10:13 -0700431 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800432 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800433 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800434 Bundle.setDefusable(extras, true);
435
436 final int callingUid = Binder.getCallingUid();
437 if (Log.isLoggable(TAG, Log.VERBOSE)) {
438 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
439 + ", pid " + Binder.getCallingPid());
440 }
441 Preconditions.checkNotNull(account, "account cannot be null");
442 int userId = UserHandle.getCallingUserId();
443 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
444 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
445 callingUid, account.type);
446 throw new SecurityException(msg);
447 }
448 /*
449 * Child users are not allowed to add accounts. Only the accounts that are shared by the
450 * parent profile can be added to child profile.
451 *
452 * TODO: Only allow accounts that were shared to be added by a limited user.
453 */
454 // fails if the account already exists
455 long identityToken = clearCallingIdentity();
456 try {
457 UserAccounts accounts = getUserAccounts(userId);
458 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800459 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800460 } finally {
461 restoreCallingIdentity(identityToken);
462 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700463 }
464
465 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800466 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
467 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800468 int callingUid = Binder.getCallingUid();
469 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
470 List<String> managedTypes =
471 getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
472
473 if ((accountType != null && !managedTypes.contains(accountType))
474 || (accountType == null && !isSystemUid)) {
475 throw new SecurityException(
476 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
477 + callingUid + " with packageName=" + packageName);
478 }
479 if (accountType != null) {
480 managedTypes = new ArrayList<String>();
481 managedTypes.add(accountType);
482 }
483
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800484 long identityToken = clearCallingIdentity();
485 try {
486 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
487 getUserAccounts(UserHandle.getUserId(callingUid)));
488 } finally {
489 restoreCallingIdentity(identityToken);
490 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800491 }
492
493 /*
494 * accountTypes may not be null
495 */
496 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
497 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
498 int uid = 0;
499 try {
500 uid = mPackageManager.getPackageUidAsUser(packageName,
501 UserHandle.getUserId(callingUid));
502 } catch (NameNotFoundException e) {
503 Log.d(TAG, "Package not found " + e.getMessage());
504 return new HashMap<>();
505 }
506
507 Map<Account, Integer> result = new HashMap<>();
508 for (String accountType : accountTypes) {
509 synchronized (accounts.cacheLock) {
510 final Account[] accountsOfType = accounts.accountCache.get(accountType);
511 if (accountsOfType != null) {
512 for (Account account : accountsOfType) {
513 result.put(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800514 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800515 }
516 }
517 }
518 }
519 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800520 }
521
522 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800523 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800524 if (account == null) throw new IllegalArgumentException("account is null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700525 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800526 int userId = UserHandle.getUserId(callingUid);
527 UserAccounts accounts = getUserAccounts(userId);
528 if (!isAccountManagedByCaller(account.type, callingUid, userId)
529 && !isSystemUid(callingUid)) {
530 String msg =
531 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700532 throw new SecurityException(msg);
533 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800534 return getPackagesAndVisibilityForAccount(account, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800535 }
536
537 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800538 * Returns all package names and visibility values, which were set for given account.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800539 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800540 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800541 * @param accounts UserAccount that currently hosts the account and application
542 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800543 * @return Map from package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800544 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800545 private Map<String, Integer> getPackagesAndVisibilityForAccount(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800546 UserAccounts accounts) {
547 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
548 try {
549 return accounts.accountsDb.findAllVisibilityValuesForAccount(account);
550 } finally {
551 StrictMode.setThreadPolicy(oldPolicy);
552 }
553
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700554 }
555
556 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800557 public int getAccountVisibility(Account a, String packageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800558 if (a == null) throw new IllegalArgumentException("account is null");
559 int callingUid = Binder.getCallingUid();
560 if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
561 && !isSystemUid(callingUid)) {
562 String msg = String.format(
563 "uid %s cannot get secrets for accounts of type: %s",
564 callingUid,
565 a.type);
566 throw new SecurityException(msg);
567 }
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800568 return resolveAccountVisibility(a, packageName,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800569 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800570 }
571
572 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800573 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800574 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800575 * @param account The account to check visibility.
576 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800577 * @param accounts UserAccount that currently hosts the account and application
578 *
579 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
580 *
581 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800582 private int getAccountVisibility(Account account, String packageName, UserAccounts accounts) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800583 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
584 try {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800585 Integer visibility = accounts.accountsDb.findAccountVisibility(account, packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800586 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
587 } finally {
588 StrictMode.setThreadPolicy(oldPolicy);
589 }
590 }
591
592 /**
593 * Method which handles default values for Account visibility.
594 *
595 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800596 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800597 * @param accounts UserAccount that currently hosts the account and application
598 *
599 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
600 *
601 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800602 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800603 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800604 Preconditions.checkNotNull(packageName, "packageName cannot be null");
605
606 int uid = -1;
607 try {
608 long identityToken = clearCallingIdentity();
609 try {
610 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
611 } finally {
612 restoreCallingIdentity(identityToken);
613 }
614 } catch (NameNotFoundException e) {
615 Log.d(TAG, "Package not found " + e.getMessage());
616 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800617 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800618
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800619 // System visibility can not be restricted.
620 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
621 return AccountManager.VISIBILITY_VISIBLE;
622 }
623
624 int signatureCheckResult =
625 checkPackageSignature(account.type, uid, accounts.userId);
626
627 // Authenticator can not restrict visibility to itself.
628 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
629 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
630 }
631
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800632 if (isSpecialPackageKey(packageName)) {
633 Log.d(TAG, "Package name is forbidden: " + packageName);
634 return AccountManager.VISIBILITY_NOT_VISIBLE;
635 }
636
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800637 // Return stored value if it was set.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800638 int visibility = getAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800639
640 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
641 return visibility;
642 }
643
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800644 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
645 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
646
647 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800648 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800649 return AccountManager.VISIBILITY_VISIBLE;
650 }
651 // Apps with READ_CONTACTS permission get visibility by default even post O.
652 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
653
654 boolean preO = isPreOApplication(packageName);
655 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
656 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800657 || canReadContacts || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800658 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
659 // match.
660 visibility = getAccountVisibility(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800661 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800662 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
663 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
664 }
665 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800666 visibility = getAccountVisibility(account,
667 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800668 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
669 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
670 }
671 }
672 return visibility;
673 }
674
675 /**
676 * Checks targetSdk for a package;
677 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800678 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800679 *
680 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
681 * undefined
682 */
683 private boolean isPreOApplication(String packageName) {
684 try {
685 long identityToken = clearCallingIdentity();
686 ApplicationInfo applicationInfo;
687 try {
688 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
689 } finally {
690 restoreCallingIdentity(identityToken);
691 }
692
693 if (applicationInfo != null) {
694 int version = applicationInfo.targetSdkVersion;
695 return version < android.os.Build.VERSION_CODES.O;
696 }
697 return true;
698 } catch (NameNotFoundException e) {
699 Log.d(TAG, "Package not found " + e.getMessage());
700 return true;
701 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800702 }
703
704 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800705 public boolean setAccountVisibility(Account a, String packageName, int newVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800706 if (a == null) throw new IllegalArgumentException("account is null");
707 int callingUid = Binder.getCallingUid();
708 if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
709 && !isSystemUid(callingUid)) {
710 String msg = String.format(
711 "uid %s cannot get secrets for accounts of type: %s",
712 callingUid,
713 a.type);
714 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700715 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800716 return setAccountVisibility(a, packageName, newVisibility, true /* notify */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800717 getUserAccounts(UserHandle.getUserId(callingUid)));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700718 }
719
720 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800721 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700722 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800723 * @param account Account to update visibility.
724 * @param packageName Package name for which visibility is updated.
725 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800726 * @param notify if the flag is set applications will get notification about visibility change
727 * @param accounts UserAccount that currently hosts the account and application
728 *
729 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700730 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800731 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800732 boolean notify, UserAccounts accounts) {
733 synchronized (accounts.cacheLock) {
734 LinkedHashSet<String> interestedPackages;
735 if (notify) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800736 if (isSpecialPackageKey(packageName)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800737 interestedPackages = getRequestingPackageNames(account.type, accounts);
738 } 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 Dementyeve366f822017-01-31 10:25:10 -0800742 interestedPackages = new LinkedHashSet<>();
743 interestedPackages.add(packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800744 }
745 } else {
746 // Notifications will not be send.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800747 if (!isSpecialPackageKey(packageName) &&
748 !packageExistsForUser(packageName, accounts.userId)) {
749 // package is not installed and not meta value.
750 return false;
751 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800752 interestedPackages = new LinkedHashSet<>();
753 }
754 Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
755
756 final long accountId = accounts.accountsDb.findDeAccountId(account);
757 if (accountId < 0) {
758 return false;
759 }
760 int index = 0;
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800761 for (String interestedPackage : interestedPackages) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800762 interestedPackagesVisibility[index++] =
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800763 resolveAccountVisibility(account, interestedPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800764 }
765
766 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
767 try {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800768 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
769 newVisibility)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800770 return false;
771 }
772 } finally {
773 StrictMode.setThreadPolicy(oldPolicy);
774 }
775
776 index = 0;
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800777 for (String interestedPackage : interestedPackages) {
778 int visibility = resolveAccountVisibility(account, interestedPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800779 if (visibility != interestedPackagesVisibility[index++]) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800780 sendNotification(interestedPackage, account, accounts.userId);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700781 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700782 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800783 if (notify) {
784 sendAccountsChangedBroadcast(accounts.userId);
785 }
786 return true;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700787 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700788 }
789
790 /**
Dmitry Dementyev52745472016-12-02 10:27:45 -0800791 * Sends a direct intent to a package, notifying it of a visible account change.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700792 *
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800793 * @param packageName to send Account to
794 * @param account to send to package
795 * @param userId User
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700796 */
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800797 private void sendNotification(String packageName, Account account, int userId) {
798 // TODO send notification so apps subscribed in runtime.
799 }
800
801 private void sendNotification(Account account, UserAccounts accounts) {
802 LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
803 accounts);
804 for (String packageName : interestedPackages) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800805 int visibility = resolveAccountVisibility(account, packageName, accounts);
806 if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
807 sendNotification(packageName, account, accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800808 }
809 }
810 }
811
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800812 LinkedHashSet<String> getRequestingPackageNames(String accountType, UserAccounts accounts) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800813 // TODO return packages registered to get notifications.
814 return new LinkedHashSet<String>();
815 }
816
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800817 private boolean packageExistsForUser(String packageName, int userId) {
818 try {
819 long identityToken = clearCallingIdentity();
820 try {
821 mPackageManager.getPackageUidAsUser(packageName, userId);
822 return true; // package exist
823 } finally {
824 restoreCallingIdentity(identityToken);
825 }
826 } catch (NameNotFoundException e) {
827 return false;
828 }
829 }
830
831 /**
832 * Returns true if packageName is one of special values.
833 */
834 private boolean isSpecialPackageKey(String packageName) {
835 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
836 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
837 }
838
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800839 private void sendAccountsChangedBroadcast(int userId) {
840 Log.i(TAG, "the accounts changed, sending broadcast of "
841 + ACCOUNTS_CHANGED_INTENT.getAction());
842 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700843 }
844
845 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700846 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
847 throws RemoteException {
848 try {
849 return super.onTransact(code, data, reply, flags);
850 } catch (RuntimeException e) {
851 // The account manager only throws security exceptions, so let's
852 // log all others.
853 if (!(e instanceof SecurityException)) {
854 Slog.wtf(TAG, "Account Manager Crash", e);
855 }
856 throw e;
857 }
858 }
859
Amith Yamasani258848d2012-08-10 17:06:33 -0700860 private UserManager getUserManager() {
861 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700862 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700863 }
864 return mUserManager;
865 }
866
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700867 /**
868 * Validate internal set of accounts against installed authenticators for
869 * given user. Clears cached authenticators before validating.
870 */
871 public void validateAccounts(int userId) {
872 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700873 // Invalidate user-specific cache to make sure we catch any
874 // removed authenticators.
875 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
876 }
877
878 /**
879 * Validate internal set of accounts against installed authenticators for
880 * given user. Clear cached authenticators before validating when requested.
881 */
882 private void validateAccountsInternal(
883 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700884 if (Log.isLoggable(TAG, Log.DEBUG)) {
885 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700886 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600887 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700888 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700889
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700890 if (invalidateAuthenticatorCache) {
891 mAuthenticatorCache.invalidateCache(accounts.userId);
892 }
893
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700894 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
895 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700896 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700897
Amith Yamasani04e0d262012-02-14 11:50:53 -0800898 synchronized (accounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800899 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800900
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700901 // Get a map of stored authenticator types to UID
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700902 final AccountsDb accountsDb = accounts.accountsDb;
903 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800904 // Create a list of authenticator type whose previous uid no longer exists
905 HashSet<String> obsoleteAuthType = Sets.newHashSet();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700906 SparseBooleanArray knownUids = null;
907 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
908 String type = authToUidEntry.getKey();
909 int uid = authToUidEntry.getValue();
910 Integer knownUid = knownAuth.get(type);
911 if (knownUid != null && uid == knownUid) {
912 // Remove it from the knownAuth list if it's unchanged.
913 knownAuth.remove(type);
914 } else {
915 /*
916 * The authenticator is presently not cached and should only be triggered
917 * when we think an authenticator has been removed (or is being updated).
918 * But we still want to check if any data with the associated uid is
919 * around. This is an (imperfect) signal that the package may be updating.
920 *
921 * A side effect of this is that an authenticator sharing a uid with
922 * multiple apps won't get its credentials wiped as long as some app with
923 * that uid is still on the device. But I suspect that this is a rare case.
924 * And it isn't clear to me how an attacker could really exploit that
925 * feature.
926 *
927 * The upshot is that we don't have to worry about accounts getting
928 * uninstalled while the authenticator's package is being updated.
929 *
930 */
931 if (knownUids == null) {
932 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800933 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700934 if (!knownUids.get(uid)) {
935 // The authenticator is not presently available to the cache. And the
936 // package no longer has a data directory (so we surmise it isn't updating).
937 // So purge its data from the account databases.
938 obsoleteAuthType.add(type);
939 // And delete it from the TABLE_META
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700940 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800941 }
942 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800943 }
944
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700945 // Add the newly registered authenticator to TABLE_META. If old authenticators have
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700946 // been re-enabled (after being updated for example), then we just overwrite the old
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700947 // values.
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700948 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700949 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800950 }
951
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700952 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800953 try {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800954 accounts.accountCache.clear();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700955 final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700956 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
957 final long accountId = accountEntry.getKey();
958 final Account account = accountEntry.getValue();
959 if (obsoleteAuthType.contains(account.type)) {
960 Slog.w(TAG, "deleting account " + account.name + " because type "
961 + account.type + "'s registered authenticator no longer exist.");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700962 accountsDb.beginTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700963 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700964 accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700965 // Also delete from CE table if user is unlocked; if user is currently
966 // locked the account will be removed later by syncDeCeAccountsLocked
967 if (userUnlocked) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700968 accountsDb.deleteCeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700969 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700970 accountsDb.setTransactionSuccessful();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700971 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700972 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700973 }
Fred Quintana56285a62010-12-02 14:20:51 -0800974 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700975
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700976 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
977 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700978
Amith Yamasani04e0d262012-02-14 11:50:53 -0800979 accounts.userDataCache.remove(account);
980 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700981 accounts.accountTokenCaches.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800982 LinkedHashSet<String> interestedPackages =
983 getRequestingPackageNames(account.type, accounts);
984 for (String packageName : interestedPackages) {
985 sendNotification(packageName, null, accounts.userId);
986 }
987
Fred Quintana56285a62010-12-02 14:20:51 -0800988 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700989 ArrayList<String> accountNames = accountNamesByType.get(account.type);
Fred Quintana56285a62010-12-02 14:20:51 -0800990 if (accountNames == null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700991 accountNames = new ArrayList<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700992 accountNamesByType.put(account.type, accountNames);
Fred Quintana56285a62010-12-02 14:20:51 -0800993 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700994 accountNames.add(account.name);
Fred Quintana56285a62010-12-02 14:20:51 -0800995 }
996 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700997 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
Fred Quintana56285a62010-12-02 14:20:51 -0800998 final String accountType = cur.getKey();
999 final ArrayList<String> accountNames = cur.getValue();
1000 final Account[] accountsForType = new Account[accountNames.size()];
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001001 for (int i = 0; i < accountsForType.length; i++) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07001002 accountsForType[i] = new Account(accountNames.get(i), accountType,
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001003 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001004 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001005 accounts.accountCache.put(accountType, accountsForType);
Fred Quintanaafa92b82009-12-01 16:27:03 -08001006 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001007 } finally {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001008 if (accountDeleted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001009 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001010 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001011 }
1012 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001013 }
1014
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001015 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1016 // Get the UIDs of all apps that might have data on the device. We want
1017 // to preserve user data if the app might otherwise be storing data.
1018 List<PackageInfo> pkgsWithData =
1019 mPackageManager.getInstalledPackagesAsUser(
1020 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1021 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1022 for (PackageInfo pkgInfo : pkgsWithData) {
1023 if (pkgInfo.applicationInfo != null
1024 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1025 knownUids.put(pkgInfo.applicationInfo.uid, true);
1026 }
1027 }
1028 return knownUids;
1029 }
1030
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001031 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001032 Context context,
1033 int userId) {
1034 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001035 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1036 }
1037
1038 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1039 IAccountAuthenticatorCache authCache,
1040 int userId) {
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001041 HashMap<String, Integer> knownAuth = new HashMap<>();
1042 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1043 .getAllServices(userId)) {
1044 knownAuth.put(service.type.type, service.uid);
1045 }
1046 return knownAuth;
1047 }
1048
Amith Yamasani04e0d262012-02-14 11:50:53 -08001049 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001050 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001051 }
1052
1053 protected UserAccounts getUserAccounts(int userId) {
1054 synchronized (mUsers) {
1055 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001056 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001057 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001058 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1059 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001060 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001061 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001062 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001063 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001064 validateAccounts = true;
1065 }
1066 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001067 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001068 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
1069 synchronized (accounts.cacheLock) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001070 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001071 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001072 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001073 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001074 }
1075 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001076 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001077 }
1078 return accounts;
1079 }
1080 }
1081
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001082 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1083 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001084 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001085 if (!accountsToRemove.isEmpty()) {
1086 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1087 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001088 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1089 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001090
1091 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001092 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001093 }
1094 }
1095 }
1096
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001097 private void purgeOldGrantsAll() {
1098 synchronized (mUsers) {
1099 for (int i = 0; i < mUsers.size(); i++) {
1100 purgeOldGrants(mUsers.valueAt(i));
1101 }
1102 }
1103 }
1104
1105 private void purgeOldGrants(UserAccounts accounts) {
1106 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001107 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001108 for (int uid : uids) {
1109 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1110 if (packageExists) {
1111 continue;
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001112 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001113 Log.d(TAG, "deleting grants for UID " + uid
1114 + " because its package is no longer installed");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001115 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001116 }
1117 }
1118 }
1119
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001120 private void removeVisibilityValuesForPackage(String packageName) {
1121 synchronized (mUsers) {
1122 for (int i = 0; i < mUsers.size(); i++) {
1123 UserAccounts accounts = mUsers.valueAt(i);
1124 try {
1125 int uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1126 } catch (NameNotFoundException e) {
1127 // package does not exist - remove visibility values
1128 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
1129 }
1130 }
1131 }
1132 }
1133
Amith Yamasani13593602012-03-22 16:16:17 -07001134 private void onUserRemoved(Intent intent) {
Amith Yamasani2a003292012-08-14 18:25:45 -07001135 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Amith Yamasani13593602012-03-22 16:16:17 -07001136 if (userId < 1) return;
1137
1138 UserAccounts accounts;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001139 boolean userUnlocked;
Amith Yamasani13593602012-03-22 16:16:17 -07001140 synchronized (mUsers) {
1141 accounts = mUsers.get(userId);
1142 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001143 userUnlocked = mLocalUnlockedUsers.get(userId);
1144 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001145 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001146 if (accounts != null) {
1147 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001148 accounts.accountsDb.close();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001149 }
Amith Yamasani13593602012-03-22 16:16:17 -07001150 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001151 Log.i(TAG, "Removing database files for user " + userId);
Fyodor Kupolovda993802016-09-21 14:47:10 -07001152 File dbFile = new File(mInjector.getDeDatabaseName(userId));
Amith Yamasani13593602012-03-22 16:16:17 -07001153
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001154 AccountsDb.deleteDbFileWarnIfFailed(dbFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001155 // Remove CE file if user is unlocked, or FBE is not enabled
1156 boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
1157 if (!fbeEnabled || userUnlocked) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001158 File ceDb = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001159 if (ceDb.exists()) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001160 AccountsDb.deleteDbFileWarnIfFailed(ceDb);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001161 }
1162 }
1163 }
1164
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001165 @VisibleForTesting
1166 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001167 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1168 }
1169
1170 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001171 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1172 Log.v(TAG, "onUserUnlocked " + userId);
1173 }
1174 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001175 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001176 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001177 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001178 syncSharedAccounts(userId);
1179 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001180
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001181 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001182 // Check if there's a shared account that needs to be created as an account
1183 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1184 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001185 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001186 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001187 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001188 : UserHandle.USER_SYSTEM;
1189 if (parentUserId < 0) {
1190 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1191 return;
1192 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001193 for (Account sa : sharedAccounts) {
1194 if (ArrayUtils.contains(accounts, sa)) continue;
1195 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001196 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001197 }
1198 }
1199
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001200 @Override
1201 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001202 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001203 }
1204
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001205 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001206 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001207 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001208 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1209 Log.v(TAG, "getPassword: " + account
1210 + ", caller's uid " + Binder.getCallingUid()
1211 + ", pid " + Binder.getCallingPid());
1212 }
Fred Quintana382601f2010-03-25 12:25:10 -07001213 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001214 int userId = UserHandle.getCallingUserId();
1215 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001216 String msg = String.format(
1217 "uid %s cannot get secrets for accounts of type: %s",
1218 callingUid,
1219 account.type);
1220 throw new SecurityException(msg);
1221 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001222 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001223 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001224 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001225 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001226 } finally {
1227 restoreCallingIdentity(identityToken);
1228 }
1229 }
1230
Amith Yamasani04e0d262012-02-14 11:50:53 -08001231 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001232 if (account == null) {
1233 return null;
1234 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001235 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001236 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1237 return null;
1238 }
Fred Quintana31957f12009-10-21 13:43:10 -07001239
Amith Yamasani04e0d262012-02-14 11:50:53 -08001240 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001241 return accounts.accountsDb.findAccountPasswordByNameAndType(account.name, account.type);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001242 }
1243 }
1244
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001245 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001246 public String getPreviousName(Account account) {
1247 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1248 Log.v(TAG, "getPreviousName: " + account
1249 + ", caller's uid " + Binder.getCallingUid()
1250 + ", pid " + Binder.getCallingPid());
1251 }
1252 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001253 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001254 long identityToken = clearCallingIdentity();
1255 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001256 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001257 return readPreviousNameInternal(accounts, account);
1258 } finally {
1259 restoreCallingIdentity(identityToken);
1260 }
1261 }
1262
1263 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1264 if (account == null) {
1265 return null;
1266 }
1267 synchronized (accounts.cacheLock) {
1268 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1269 if (previousNameRef == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001270 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001271 previousNameRef = new AtomicReference<>(previousName);
1272 accounts.previousNameCache.put(account, previousNameRef);
1273 return previousName;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001274 } else {
1275 return previousNameRef.get();
1276 }
1277 }
1278 }
1279
1280 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001281 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001282 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001283 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001284 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1285 account, key, callingUid, Binder.getCallingPid());
1286 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001287 }
Fred Quintana382601f2010-03-25 12:25:10 -07001288 if (account == null) throw new IllegalArgumentException("account is null");
1289 if (key == null) throw new IllegalArgumentException("key is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001290 int userId = UserHandle.getCallingUserId();
1291 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001292 String msg = String.format(
1293 "uid %s cannot get user data for accounts of type: %s",
1294 callingUid,
1295 account.type);
1296 throw new SecurityException(msg);
1297 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001298 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001299 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1300 return null;
1301 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001302 long identityToken = clearCallingIdentity();
1303 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001304 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00001305 synchronized (accounts.cacheLock) {
1306 if (!accountExistsCacheLocked(accounts, account)) {
1307 return null;
1308 }
1309 return readUserDataInternalLocked(accounts, account, key);
1310 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001311 } finally {
1312 restoreCallingIdentity(identityToken);
1313 }
1314 }
1315
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001316 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001317 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001318 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001319 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1320 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001321 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001322 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001323 + ", pid " + Binder.getCallingPid());
1324 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001325 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001326 if (isCrossUser(callingUid, userId)) {
1327 throw new SecurityException(
1328 String.format(
1329 "User %s tying to get authenticator types for %s" ,
1330 UserHandle.getCallingUserId(),
1331 userId));
1332 }
1333
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001334 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001335 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001336 return getAuthenticatorTypesInternal(userId);
1337
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001338 } finally {
1339 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001340 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001341 }
1342
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001343 /**
1344 * Should only be called inside of a clearCallingIdentity block.
1345 */
1346 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001347 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001348 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1349 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1350 AuthenticatorDescription[] types =
1351 new AuthenticatorDescription[authenticatorCollection.size()];
1352 int i = 0;
1353 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1354 : authenticatorCollection) {
1355 types[i] = authenticator.type;
1356 i++;
1357 }
1358 return types;
1359 }
1360
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001361 private boolean isCrossUser(int callingUid, int userId) {
1362 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001363 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001364 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001365 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1366 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001367 }
1368
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001369 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001370 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001371 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001372 }
1373
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001374 @Override
1375 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001376 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001377 int callingUid = Binder.getCallingUid();
1378 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1379 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001380 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001381 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001382 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1383 final UserAccounts toAccounts = getUserAccounts(userTo);
1384 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001385 if (response != null) {
1386 Bundle result = new Bundle();
1387 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1388 try {
1389 response.onResult(result);
1390 } catch (RemoteException e) {
1391 Slog.w(TAG, "Failed to report error back to the client." + e);
1392 }
1393 }
1394 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001395 }
1396
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001397 Slog.d(TAG, "Copying account " + account.name
1398 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001399 long identityToken = clearCallingIdentity();
1400 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001401 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001402 false /* stripAuthTokenFromResult */, account.name,
1403 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001404 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001405 protected String toDebugString(long now) {
1406 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1407 + ", " + account.type;
1408 }
1409
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001410 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001411 public void run() throws RemoteException {
1412 mAuthenticator.getAccountCredentialsForCloning(this, account);
1413 }
1414
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001415 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001416 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001417 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001418 if (result != null
1419 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1420 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001421 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001422 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001423 super.onResult(result);
1424 }
1425 }
1426 }.bind();
1427 } finally {
1428 restoreCallingIdentity(identityToken);
1429 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001430 }
1431
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001432 @Override
1433 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001434 final int callingUid = Binder.getCallingUid();
1435 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1436 String msg = String.format(
1437 "accountAuthenticated( account: %s, callerUid: %s)",
1438 account,
1439 callingUid);
1440 Log.v(TAG, msg);
1441 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001442 if (account == null) {
1443 throw new IllegalArgumentException("account is null");
1444 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001445 int userId = UserHandle.getCallingUserId();
1446 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001447 String msg = String.format(
1448 "uid %s cannot notify authentication for accounts of type: %s",
1449 callingUid,
1450 account.type);
1451 throw new SecurityException(msg);
1452 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001453
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001454 if (!canUserModifyAccounts(userId, callingUid) ||
1455 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001456 return false;
1457 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001458
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001459 long identityToken = clearCallingIdentity();
1460 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001461 UserAccounts accounts = getUserAccounts(userId);
1462 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001463 } finally {
1464 restoreCallingIdentity(identityToken);
1465 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001466 }
1467
1468 private boolean updateLastAuthenticatedTime(Account account) {
1469 final UserAccounts accounts = getUserAccountsForCaller();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001470 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001471 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001472 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001473 }
1474
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001475 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001476 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1477 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001478 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001479 long id = clearCallingIdentity();
1480 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001481 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001482 false /* stripAuthTokenFromResult */, account.name,
1483 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001484 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001485 protected String toDebugString(long now) {
1486 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1487 + ", " + account.type;
1488 }
1489
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001490 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001491 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001492 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001493 UserAccounts owner = getUserAccounts(parentUserId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001494 synchronized (owner.cacheLock) {
Svetoslavf3f02ac2015-09-08 14:36:35 -07001495 for (Account acc : getAccounts(parentUserId,
1496 mContext.getOpPackageName())) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001497 if (acc.equals(account)) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001498 mAuthenticator.addAccountFromCredentials(
1499 this, account, accountCredentials);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001500 break;
1501 }
1502 }
1503 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001504 }
1505
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001506 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001507 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001508 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001509 // TODO: Anything to do if if succedded?
1510 // TODO: If it failed: Show error notification? Should we remove the shadow
1511 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001512 // TODO: what we do with the visibility?
1513
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001514 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001515 }
1516
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001517 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001518 public void onError(int errorCode, String errorMessage) {
1519 super.onError(errorCode, errorMessage);
1520 // TODO: Show error notification to user
1521 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1522 }
1523
1524 }.bind();
1525 } finally {
1526 restoreCallingIdentity(id);
1527 }
1528 }
1529
Amith Yamasani04e0d262012-02-14 11:50:53 -08001530 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001531 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001532 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001533 if (account == null) {
1534 return false;
1535 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001536 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001537 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1538 + " is locked. callingUid=" + callingUid);
1539 return false;
1540 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001541 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001542 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001543 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001544 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001545 Log.w(TAG, "insertAccountIntoDatabase: " + account
1546 + ", skipping since the account already exists");
1547 return false;
1548 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001549 long accountId = accounts.accountsDb.insertCeAccount(account, password);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001550 if (accountId < 0) {
1551 Log.w(TAG, "insertAccountIntoDatabase: " + account
1552 + ", skipping the DB insert failed");
1553 return false;
1554 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001555 // Insert into DE table
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001556 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001557 Log.w(TAG, "insertAccountIntoDatabase: " + account
1558 + ", skipping the DB insert failed");
1559 return false;
1560 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001561 if (extras != null) {
1562 for (String key : extras.keySet()) {
1563 final String value = extras.getString(key);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001564 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001565 Log.w(TAG, "insertAccountIntoDatabase: " + account
1566 + ", skipping since insertExtra failed for key " + key);
1567 return false;
1568 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001569 }
1570 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001571
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001572 if (packageToVisibility != null) {
1573 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1574 setAccountVisibility(account, entry.getKey() /* package */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001575 entry.getValue() /* visibility */, false /* notify */, accounts);
1576 }
1577 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001578 accounts.accountsDb.setTransactionSuccessful();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001579
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001580 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
1581 accounts, callingUid);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001582
Amith Yamasani04e0d262012-02-14 11:50:53 -08001583 insertAccountIntoCacheLocked(accounts, account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001584 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001585 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001586 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001587 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001588 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1589 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001590 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001591
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001592 sendNotification(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001593 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1594 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001595
Amith Yamasani5be347b2013-03-31 17:44:31 -07001596 return true;
1597 }
1598
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001599 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001600 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001601 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001602 }
1603 }
1604
Amith Yamasani5be347b2013-03-31 17:44:31 -07001605 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001606 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001607 * running, then clone the account too.
1608 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001609 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001610 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001611 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001612 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001613 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001614 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001615 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001616 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001617 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001618 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001619 }
1620 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001621 }
1622 }
1623
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001624 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001625 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001626 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001627 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001628 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001629 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1630 Log.v(TAG, "hasFeatures: " + account
1631 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001632 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001633 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001634 + ", pid " + Binder.getCallingPid());
1635 }
Fred Quintana382601f2010-03-25 12:25:10 -07001636 if (response == null) throw new IllegalArgumentException("response is null");
1637 if (account == null) throw new IllegalArgumentException("account is null");
1638 if (features == null) throw new IllegalArgumentException("features is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001639 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001640 checkReadAccountsPermitted(callingUid, account.type, userId,
1641 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001642
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001643 long identityToken = clearCallingIdentity();
1644 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001645 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001646 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001647 } finally {
1648 restoreCallingIdentity(identityToken);
1649 }
1650 }
1651
1652 private class TestFeaturesSession extends Session {
1653 private final String[] mFeatures;
1654 private final Account mAccount;
1655
Amith Yamasani04e0d262012-02-14 11:50:53 -08001656 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001657 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001658 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001659 true /* stripAuthTokenFromResult */, account.name,
1660 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001661 mFeatures = features;
1662 mAccount = account;
1663 }
1664
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001665 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001666 public void run() throws RemoteException {
1667 try {
1668 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1669 } catch (RemoteException e) {
1670 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1671 }
1672 }
1673
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001674 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001675 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001676 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001677 IAccountManagerResponse response = getResponseAndClose();
1678 if (response != null) {
1679 try {
1680 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001681 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001682 return;
1683 }
Fred Quintana56285a62010-12-02 14:20:51 -08001684 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1685 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1686 + response);
1687 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001688 final Bundle newResult = new Bundle();
1689 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1690 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1691 response.onResult(newResult);
1692 } catch (RemoteException e) {
1693 // if the caller is dead then there is no one to care about remote exceptions
1694 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1695 Log.v(TAG, "failure while notifying response", e);
1696 }
1697 }
1698 }
1699 }
1700
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001701 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001702 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001703 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001704 + ", " + mAccount
1705 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1706 }
1707 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001708
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001709 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001710 public void renameAccount(
1711 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001712 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001713 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1714 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001715 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001716 + ", pid " + Binder.getCallingPid());
1717 }
1718 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001719 int userId = UserHandle.getCallingUserId();
1720 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001721 String msg = String.format(
1722 "uid %s cannot rename accounts of type: %s",
1723 callingUid,
1724 accountToRename.type);
1725 throw new SecurityException(msg);
1726 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001727 long identityToken = clearCallingIdentity();
1728 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001729 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001730 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001731 Bundle result = new Bundle();
1732 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1733 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001734 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1735 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001736 try {
1737 response.onResult(result);
1738 } catch (RemoteException e) {
1739 Log.w(TAG, e.getMessage());
1740 }
1741 } finally {
1742 restoreCallingIdentity(identityToken);
1743 }
1744 }
1745
1746 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001747 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001748 Account resultAccount = null;
1749 /*
1750 * Cancel existing notifications. Let authenticators
1751 * re-post notifications as required. But we don't know if
1752 * the authenticators have bound their notifications to
1753 * now stale account name data.
1754 *
1755 * With a rename api, we might not need to do this anymore but it
1756 * shouldn't hurt.
1757 */
1758 cancelNotification(
1759 getSigninRequiredNotificationId(accounts, accountToRename),
1760 new UserHandle(accounts.userId));
1761 synchronized(accounts.credentialsPermissionNotificationIds) {
1762 for (Pair<Pair<Account, String>, Integer> pair:
1763 accounts.credentialsPermissionNotificationIds.keySet()) {
1764 if (accountToRename.equals(pair.first.first)) {
1765 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1766 cancelNotification(id, new UserHandle(accounts.userId));
1767 }
1768 }
1769 }
1770 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001771 accounts.accountsDb.beginTransaction();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001772 Account renamedAccount = new Account(newName, accountToRename.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001773 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1774 Log.e(TAG, "renameAccount failed - account with new name already exists");
1775 return null;
1776 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001777 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001778 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001779 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001780 accounts.accountsDb.renameCeAccount(accountId, newName);
Dmitry Dementyevcf50dcf2016-11-17 14:14:11 -08001781 if (accounts.accountsDb.renameDeAccount(
1782 accountId, newName, accountToRename.name)) {
1783 accounts.accountsDb.setTransactionSuccessful();
1784 } else {
1785 Log.e(TAG, "renameAccount failed");
1786 return null;
1787 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001788 } else {
1789 Log.e(TAG, "renameAccount failed - old account does not exist");
1790 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001791 }
1792 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001793 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001794 }
1795 /*
1796 * Database transaction was successful. Clean up cached
1797 * data associated with the account in the user profile.
1798 */
Svet Ganov5c4a5122016-09-23 19:29:11 -07001799 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001800 /*
1801 * Extract the data and token caches before removing the
1802 * old account to preserve the user data associated with
1803 * the account.
1804 */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001805 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1806 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001807 removeAccountFromCacheLocked(accounts, accountToRename);
1808 /*
1809 * Update the cached data associated with the renamed
1810 * account.
1811 */
1812 accounts.userDataCache.put(renamedAccount, tmpData);
1813 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1814 accounts.previousNameCache.put(
1815 renamedAccount,
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001816 new AtomicReference<>(accountToRename.name));
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001817 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001818
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001819 int parentUserId = accounts.userId;
1820 if (canHaveProfile(parentUserId)) {
1821 /*
1822 * Owner or system user account was renamed, rename the account for
1823 * those users with which the account was shared.
1824 */
1825 List<UserInfo> users = getUserManager().getUsers(true);
1826 for (UserInfo user : users) {
1827 if (user.isRestricted()
1828 && (user.restrictedProfileParentId == parentUserId)) {
1829 renameSharedAccountAsUser(accountToRename, newName, user.id);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001830 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001831 }
1832 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001833
1834 // Notify authenticator.
1835 sendNotification(resultAccount, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001836 sendAccountsChangedBroadcast(accounts.userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001837 }
1838 return resultAccount;
1839 }
1840
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001841 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001842 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001843 return userInfo != null && userInfo.canHaveProfile();
1844 }
1845
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001846 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001847 public void removeAccount(IAccountManagerResponse response, Account account,
1848 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001849 removeAccountAsUser(
1850 response,
1851 account,
1852 expectActivityLaunch,
1853 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001854 }
1855
1856 @Override
1857 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001858 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001859 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001860 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1861 Log.v(TAG, "removeAccount: " + account
1862 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001863 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001864 + ", pid " + Binder.getCallingPid()
1865 + ", for user id " + userId);
1866 }
1867 if (response == null) throw new IllegalArgumentException("response is null");
1868 if (account == null) throw new IllegalArgumentException("account is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001869 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001870 if (isCrossUser(callingUid, userId)) {
1871 throw new SecurityException(
1872 String.format(
1873 "User %s tying remove account for %s" ,
1874 UserHandle.getCallingUserId(),
1875 userId));
1876 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001877 /*
1878 * Only the system or authenticator should be allowed to remove accounts for that
1879 * authenticator. This will let users remove accounts (via Settings in the system) but not
1880 * arbitrary applications (like competing authenticators).
1881 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001882 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00001883 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1884 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001885 String msg = String.format(
1886 "uid %s cannot remove accounts of type: %s",
1887 callingUid,
1888 account.type);
1889 throw new SecurityException(msg);
1890 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001891 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001892 try {
1893 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
1894 "User cannot modify accounts");
1895 } catch (RemoteException re) {
1896 }
1897 return;
1898 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001899 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001900 try {
1901 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
1902 "User cannot modify accounts of this type (policy).");
1903 } catch (RemoteException re) {
1904 }
1905 return;
1906 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001907 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001908 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001909 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001910 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001911 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08001912 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001913 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001914 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001915 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001916 }
1917 }
1918 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001919 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001920 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001921 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1922 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001923 accountId,
1924 accounts,
1925 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001926 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001927 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
1928 } finally {
1929 restoreCallingIdentity(identityToken);
1930 }
1931 }
1932
1933 @Override
1934 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001935 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001936 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1937 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001938 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001939 + ", pid " + Binder.getCallingPid());
1940 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001941 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001942 if (account == null) {
1943 /*
1944 * Null accounts should result in returning false, as per
1945 * AccountManage.addAccountExplicitly(...) java doc.
1946 */
1947 Log.e(TAG, "account is null");
1948 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001949 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001950 String msg = String.format(
1951 "uid %s cannot explicitly add accounts of type: %s",
1952 callingUid,
1953 account.type);
1954 throw new SecurityException(msg);
1955 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001956 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001957 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001958 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001959 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1960 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001961 accountId,
1962 accounts,
1963 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001964 long identityToken = clearCallingIdentity();
1965 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001966 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001967 } finally {
1968 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001969 }
Fred Quintana60307342009-03-24 22:48:12 -07001970 }
1971
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001972 private class RemoveAccountSession extends Session {
1973 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001974 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001975 Account account, boolean expectActivityLaunch) {
1976 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001977 true /* stripAuthTokenFromResult */, account.name,
1978 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001979 mAccount = account;
1980 }
1981
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001982 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001983 protected String toDebugString(long now) {
1984 return super.toDebugString(now) + ", removeAccount"
1985 + ", account " + mAccount;
1986 }
1987
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001988 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001989 public void run() throws RemoteException {
1990 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
1991 }
1992
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001993 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001994 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001995 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001996 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
1997 && !result.containsKey(AccountManager.KEY_INTENT)) {
1998 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001999 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002000 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002001 }
2002 IAccountManagerResponse response = getResponseAndClose();
2003 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002004 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2005 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2006 + response);
2007 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002008 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002009 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002010 try {
2011 response.onResult(result2);
2012 } catch (RemoteException e) {
2013 // ignore
2014 }
2015 }
2016 }
2017 super.onResult(result);
2018 }
2019 }
2020
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002021 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002022 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002023 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002024 }
2025
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002026 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002027 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002028 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002029 if (!userUnlocked) {
2030 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2031 + " is still locked. CE data will be removed later");
2032 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08002033 synchronized (accounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002034 LinkedHashSet<String> interestedPackages =
2035 accounts.mApplicationAccountRequestMappings.get(account.type);
2036 if (interestedPackages == null) {
2037 interestedPackages = new LinkedHashSet<>();
2038 }
2039 int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
2040 int index = 0;
2041 for (String packageName : interestedPackages) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08002042 int visibility = resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002043 visibilityForInterestedPackages[index++] = visibility;
2044 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002045 accounts.accountsDb.beginTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002046 // Set to a dummy value, this will only be used if the database
2047 // transaction succeeds.
2048 long accountId = -1;
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002049 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002050 accountId = accounts.accountsDb.findDeAccountId(account);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002051 if (accountId >= 0) {
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002052 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002053 }
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002054 // always delete from CE table if CE storage is available
2055 // DE account could be removed while CE was locked
2056 if (userUnlocked) {
2057 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2058 if (ceAccountId >= 0) {
2059 accounts.accountsDb.deleteCeAccount(ceAccountId);
2060 }
2061 }
2062 accounts.accountsDb.setTransactionSuccessful();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002063 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002064 accounts.accountsDb.endTransaction();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002065 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002066 if (isChanged) {
2067 removeAccountFromCacheLocked(accounts, account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002068 index = 0;
2069 for (String packageName : interestedPackages) {
2070 if ((visibilityForInterestedPackages[index]
2071 != AccountManager.VISIBILITY_NOT_VISIBLE)
2072 && (visibilityForInterestedPackages[index]
2073 != AccountManager.VISIBILITY_UNDEFINED)) {
2074 sendNotification(packageName, account, accounts.userId);
2075 }
2076 ++index;
2077 }
2078
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002079 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
2080 sendAccountsChangedBroadcast(accounts.userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002081 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2082 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2083 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002084 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002085 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002086 long id = Binder.clearCallingIdentity();
2087 try {
2088 int parentUserId = accounts.userId;
2089 if (canHaveProfile(parentUserId)) {
2090 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002091 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002092 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002093 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002094 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002095 }
2096 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002097 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002098 } finally {
2099 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002100 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002101
2102 if (isChanged) {
2103 synchronized (accounts.credentialsPermissionNotificationIds) {
2104 for (Pair<Pair<Account, String>, Integer> key
2105 : accounts.credentialsPermissionNotificationIds.keySet()) {
2106 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002107 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002108 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002109 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002110 account, uid, false));
2111 }
2112 }
2113 }
2114 }
2115
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002116 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002117 }
2118
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002119 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002120 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002121 int callerUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002122 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2123 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002124 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002125 + ", pid " + Binder.getCallingPid());
2126 }
Fred Quintana382601f2010-03-25 12:25:10 -07002127 if (accountType == null) throw new IllegalArgumentException("accountType is null");
2128 if (authToken == null) throw new IllegalArgumentException("authToken is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002129 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002130 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002131 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002132 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002133 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002134 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002135 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002136 invalidateAuthTokenLocked(accounts, accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002137 invalidateCustomTokenLocked(accounts, accountType, authToken);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002138 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002139 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002140 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002141 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002142 }
Fred Quintana60307342009-03-24 22:48:12 -07002143 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002144 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002145 }
2146 }
2147
Carlos Valdivia91979be2015-05-22 14:11:35 -07002148 private void invalidateCustomTokenLocked(
2149 UserAccounts accounts,
2150 String accountType,
2151 String authToken) {
2152 if (authToken == null || accountType == null) {
2153 return;
2154 }
2155 // Also wipe out cached token in memory.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002156 accounts.accountTokenCaches.remove(accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002157 }
2158
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002159 private void invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
2160 String authToken) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002161 if (authToken == null || accountType == null) {
2162 return;
2163 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002164 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fred Quintana33269202009-04-20 16:05:10 -07002165 try {
2166 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002167 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002168 String accountName = cursor.getString(1);
2169 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002170 accounts.accountsDb.deleteAuthToken(authTokenId);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002171 writeAuthTokenIntoCacheLocked(
2172 accounts,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002173 new Account(accountName, accountType),
2174 authTokenType,
2175 null);
Fred Quintana60307342009-03-24 22:48:12 -07002176 }
Fred Quintana33269202009-04-20 16:05:10 -07002177 } finally {
2178 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002179 }
2180 }
2181
Carlos Valdivia91979be2015-05-22 14:11:35 -07002182 private void saveCachedToken(
2183 UserAccounts accounts,
2184 Account account,
2185 String callerPkg,
2186 byte[] callerSigDigest,
2187 String tokenType,
2188 String token,
2189 long expiryMillis) {
2190
2191 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2192 return;
2193 }
2194 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002195 UserHandle.of(accounts.userId));
Carlos Valdivia91979be2015-05-22 14:11:35 -07002196 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002197 accounts.accountTokenCaches.put(
2198 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002199 }
2200 }
2201
Amith Yamasani04e0d262012-02-14 11:50:53 -08002202 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2203 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002204 if (account == null || type == null) {
2205 return false;
2206 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002207 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002208 UserHandle.of(accounts.userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002209 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002210 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002211 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002212 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002213 if (accountId < 0) {
2214 return false;
2215 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002216 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2217 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2218 accounts.accountsDb.setTransactionSuccessful();
2219 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002220 return true;
2221 }
Fred Quintana33269202009-04-20 16:05:10 -07002222 return false;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002223 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002224 accounts.accountsDb.endTransaction();
Fred Quintana33269202009-04-20 16:05:10 -07002225 }
Fred Quintana60307342009-03-24 22:48:12 -07002226 }
2227 }
2228
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002229 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002230 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002231 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002232 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2233 Log.v(TAG, "peekAuthToken: " + account
2234 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002235 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002236 + ", pid " + Binder.getCallingPid());
2237 }
Fred Quintana382601f2010-03-25 12:25:10 -07002238 if (account == null) throw new IllegalArgumentException("account is null");
2239 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002240 int userId = UserHandle.getCallingUserId();
2241 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002242 String msg = String.format(
2243 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2244 callingUid,
2245 account.type);
2246 throw new SecurityException(msg);
2247 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002248 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002249 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2250 + callingUid);
2251 return null;
2252 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002253 long identityToken = clearCallingIdentity();
2254 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002255 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002256 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002257 } finally {
2258 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002259 }
Fred Quintana60307342009-03-24 22:48:12 -07002260 }
2261
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002262 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002263 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002264 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002265 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2266 Log.v(TAG, "setAuthToken: " + account
2267 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002268 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002269 + ", pid " + Binder.getCallingPid());
2270 }
Fred Quintana382601f2010-03-25 12:25:10 -07002271 if (account == null) throw new IllegalArgumentException("account is null");
2272 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002273 int userId = UserHandle.getCallingUserId();
2274 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002275 String msg = String.format(
2276 "uid %s cannot set auth tokens associated with accounts of type: %s",
2277 callingUid,
2278 account.type);
2279 throw new SecurityException(msg);
2280 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002281 long identityToken = clearCallingIdentity();
2282 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002283 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002284 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002285 } finally {
2286 restoreCallingIdentity(identityToken);
2287 }
Fred Quintana60307342009-03-24 22:48:12 -07002288 }
2289
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002290 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002291 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002292 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002293 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2294 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002295 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002296 + ", pid " + Binder.getCallingPid());
2297 }
Fred Quintana382601f2010-03-25 12:25:10 -07002298 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002299 int userId = UserHandle.getCallingUserId();
2300 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002301 String msg = String.format(
2302 "uid %s cannot set secrets for accounts of type: %s",
2303 callingUid,
2304 account.type);
2305 throw new SecurityException(msg);
2306 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002307 long identityToken = clearCallingIdentity();
2308 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002309 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002310 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002311 } finally {
2312 restoreCallingIdentity(identityToken);
2313 }
Fred Quintana60307342009-03-24 22:48:12 -07002314 }
2315
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002316 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2317 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002318 if (account == null) {
2319 return;
2320 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002321 boolean isChanged = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002322 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002323 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002324 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002325 final long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002326 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002327 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2328 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002329 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002330 accounts.accountTokenCaches.remove(account);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002331 accounts.accountsDb.setTransactionSuccessful();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002332 // If there is an account whose password will be updated and the database
2333 // transactions succeed, then we say that a change has occured. Even if the
2334 // new password is the same as the old and there were no authtokens to delete.
2335 isChanged = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002336 String action = (password == null || password.length() == 0) ?
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002337 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2338 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2339 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
Costin Manolachef5ffe892011-01-19 09:35:32 -08002340 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002341 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002342 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002343 if (isChanged) {
2344 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002345 sendNotification(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002346 sendAccountsChangedBroadcast(accounts.userId);
2347 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002348 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002349 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002350 }
2351
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002352 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002353 public void clearPassword(Account account) {
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, "clearPassword: " + 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 }
Fred Quintana382601f2010-03-25 12:25:10 -07002360 if (account == null) throw new IllegalArgumentException("account is 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 clear passwords 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, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002373 } finally {
2374 restoreCallingIdentity(identityToken);
2375 }
Fred Quintana60307342009-03-24 22:48:12 -07002376 }
2377
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002378 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002379 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002380 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002381 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2382 Log.v(TAG, "setUserData: " + account
2383 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002384 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002385 + ", pid " + Binder.getCallingPid());
2386 }
Fred Quintana382601f2010-03-25 12:25:10 -07002387 if (key == null) throw new IllegalArgumentException("key is null");
2388 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002389 int userId = UserHandle.getCallingUserId();
2390 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002391 String msg = String.format(
2392 "uid %s cannot set user data for accounts of type: %s",
2393 callingUid,
2394 account.type);
2395 throw new SecurityException(msg);
2396 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002397 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002398 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002399 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002400 synchronized (accounts.cacheLock) {
2401 if (!accountExistsCacheLocked(accounts, account)) {
2402 return;
2403 }
2404 setUserdataInternalLocked(accounts, account, key, value);
2405 }
Fred Quintana60307342009-03-24 22:48:12 -07002406 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002407 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002408 }
2409 }
2410
Simranjit Kohli858511c2016-03-10 18:36:11 +00002411 private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
2412 if (accounts.accountCache.containsKey(account.type)) {
2413 for (Account acc : accounts.accountCache.get(account.type)) {
2414 if (acc.name.equals(account.name)) {
2415 return true;
2416 }
2417 }
2418 }
2419 return false;
2420 }
2421
2422 private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002423 String value) {
Fred Quintana31957f12009-10-21 13:43:10 -07002424 if (account == null || key == null) {
2425 return;
2426 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002427 accounts.accountsDb.beginTransaction();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002428 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002429 long accountId = accounts.accountsDb.findDeAccountId(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002430 if (accountId < 0) {
2431 return;
2432 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002433 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002434 if (extrasId < 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002435 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002436 if (extrasId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002437 return;
2438 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002439 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002440 return;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002441 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002442 writeUserDataIntoCacheLocked(accounts, account, key, value);
2443 accounts.accountsDb.setTransactionSuccessful();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002444 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002445 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002446 }
2447 }
2448
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002449 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002450 if (result == null) {
2451 Log.e(TAG, "the result is unexpectedly null", new Exception());
2452 }
2453 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2454 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2455 + response);
2456 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002457 try {
2458 response.onResult(result);
2459 } catch (RemoteException e) {
2460 // if the caller is dead then there is no one to care about remote
2461 // exceptions
2462 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2463 Log.v(TAG, "failure while notifying response", e);
2464 }
2465 }
2466 }
2467
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002468 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002469 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2470 final String authTokenType)
2471 throws RemoteException {
2472 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002473 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
2474
Fred Quintanad9640ec2012-05-23 12:37:00 -07002475 final int callingUid = getCallingUid();
2476 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002477 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002478 throw new SecurityException("can only call from system");
2479 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002480 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002481 long identityToken = clearCallingIdentity();
2482 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002483 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002484 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2485 false /* stripAuthTokenFromResult */, null /* accountName */,
2486 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002487 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002488 protected String toDebugString(long now) {
2489 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002490 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002491 + ", authTokenType " + authTokenType;
2492 }
2493
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002494 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002495 public void run() throws RemoteException {
2496 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2497 }
2498
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002499 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002500 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002501 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002502 if (result != null) {
2503 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2504 Bundle bundle = new Bundle();
2505 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2506 super.onResult(bundle);
2507 return;
2508 } else {
2509 super.onResult(result);
2510 }
2511 }
2512 }.bind();
2513 } finally {
2514 restoreCallingIdentity(identityToken);
2515 }
2516 }
2517
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002518 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002519 public void getAuthToken(
2520 IAccountManagerResponse response,
2521 final Account account,
2522 final String authTokenType,
2523 final boolean notifyOnAuthFailure,
2524 final boolean expectActivityLaunch,
2525 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002526 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002527 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2528 Log.v(TAG, "getAuthToken: " + account
2529 + ", response " + response
2530 + ", authTokenType " + authTokenType
2531 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2532 + ", expectActivityLaunch " + expectActivityLaunch
2533 + ", caller's uid " + Binder.getCallingUid()
2534 + ", pid " + Binder.getCallingPid());
2535 }
Fred Quintana382601f2010-03-25 12:25:10 -07002536 if (response == null) throw new IllegalArgumentException("response is null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002537 try {
2538 if (account == null) {
2539 Slog.w(TAG, "getAuthToken called with null account");
2540 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2541 return;
2542 }
2543 if (authTokenType == null) {
2544 Slog.w(TAG, "getAuthToken called with null authTokenType");
2545 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2546 return;
2547 }
2548 } catch (RemoteException e) {
2549 Slog.w(TAG, "Failed to report error back to the client." + e);
2550 return;
2551 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002552 int userId = UserHandle.getCallingUserId();
2553 long ident = Binder.clearCallingIdentity();
2554 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002555 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002556 try {
2557 accounts = getUserAccounts(userId);
2558 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2559 AuthenticatorDescription.newKey(account.type), accounts.userId);
2560 } finally {
2561 Binder.restoreCallingIdentity(ident);
2562 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002563
Costin Manolachea40c6302010-12-13 14:50:45 -08002564 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002565 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002566
2567 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002568 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002569 final boolean permissionGranted =
2570 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002571
Carlos Valdivia91979be2015-05-22 14:11:35 -07002572 // Get the calling package. We will use it for the purpose of caching.
2573 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002574 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002575 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002576 try {
2577 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2578 } finally {
2579 Binder.restoreCallingIdentity(ident);
2580 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002581 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2582 String msg = String.format(
2583 "Uid %s is attempting to illegally masquerade as package %s!",
2584 callerUid,
2585 callerPkg);
2586 throw new SecurityException(msg);
2587 }
2588
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002589 // let authenticator know the identity of the caller
2590 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2591 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002592
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002593 if (notifyOnAuthFailure) {
2594 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002595 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002596
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002597 long identityToken = clearCallingIdentity();
2598 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002599 // Distill the caller's package signatures into a single digest.
2600 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2601
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002602 // if the caller has permission, do the peek. otherwise go the more expensive
2603 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002604 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002605 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002606 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002607 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002608 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2609 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2610 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002611 onResult(response, result);
2612 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002613 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002614 }
2615
Carlos Valdivia91979be2015-05-22 14:11:35 -07002616 if (customTokens) {
2617 /*
2618 * Look up tokens in the new cache only if the loginOptions don't have parameters
2619 * outside of those expected to be injected by the AccountManager, e.g.
2620 * ANDORID_PACKAGE_NAME.
2621 */
2622 String token = readCachedTokenInternal(
2623 accounts,
2624 account,
2625 authTokenType,
2626 callerPkg,
2627 callerPkgSigDigest);
2628 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002629 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2630 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2631 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002632 Bundle result = new Bundle();
2633 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2634 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2635 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2636 onResult(response, result);
2637 return;
2638 }
2639 }
2640
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002641 new Session(
2642 accounts,
2643 response,
2644 account.type,
2645 expectActivityLaunch,
2646 false /* stripAuthTokenFromResult */,
2647 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002648 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002649 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002650 protected String toDebugString(long now) {
2651 if (loginOptions != null) loginOptions.keySet();
2652 return super.toDebugString(now) + ", getAuthToken"
2653 + ", " + account
2654 + ", authTokenType " + authTokenType
2655 + ", loginOptions " + loginOptions
2656 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2657 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002658
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002659 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002660 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002661 // If the caller doesn't have permission then create and return the
2662 // "grant permission" intent instead of the "getAuthToken" intent.
2663 if (!permissionGranted) {
2664 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2665 } else {
2666 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2667 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002668 }
2669
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002670 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002671 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002672 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002673 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002674 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002675 Intent intent = newGrantCredentialsPermissionIntent(
2676 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002677 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002678 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002679 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002680 authTokenType,
2681 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002682 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002683 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002684 onResult(bundle);
2685 return;
2686 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002687 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002688 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002689 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2690 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002691 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002692 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002693 "the type and name should not be empty");
2694 return;
2695 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002696 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002697 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002698 saveAuthTokenToDatabase(
2699 mAccounts,
2700 resultAccount,
2701 authTokenType,
2702 authToken);
2703 }
2704 long expiryMillis = result.getLong(
2705 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2706 if (customTokens
2707 && expiryMillis > System.currentTimeMillis()) {
2708 saveCachedToken(
2709 mAccounts,
2710 account,
2711 callerPkg,
2712 callerPkgSigDigest,
2713 authTokenType,
2714 authToken,
2715 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002716 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002717 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002718
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002719 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002720 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002721 /*
2722 * Make sure that the supplied intent is owned by the authenticator
2723 * giving it to the system. Otherwise a malicious authenticator could
2724 * have users launching arbitrary activities by tricking users to
2725 * interact with malicious notifications.
2726 */
2727 checkKeyIntent(
2728 Binder.getCallingUid(),
2729 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002730 doNotification(
2731 mAccounts,
2732 account,
2733 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002734 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002735 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002736 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002737 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002738 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002739 }.bind();
2740 } finally {
2741 restoreCallingIdentity(identityToken);
2742 }
Fred Quintana60307342009-03-24 22:48:12 -07002743 }
2744
Carlos Valdivia91979be2015-05-22 14:11:35 -07002745 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2746 MessageDigest digester;
2747 try {
2748 digester = MessageDigest.getInstance("SHA-256");
2749 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2750 callerPkg, PackageManager.GET_SIGNATURES);
2751 for (Signature sig : pkgInfo.signatures) {
2752 digester.update(sig.toByteArray());
2753 }
2754 } catch (NoSuchAlgorithmException x) {
2755 Log.wtf(TAG, "SHA-256 should be available", x);
2756 digester = null;
2757 } catch (NameNotFoundException e) {
2758 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2759 digester = null;
2760 }
2761 return (digester == null) ? null : digester.digest();
2762 }
2763
Dianne Hackborn41203752012-08-31 14:05:51 -07002764 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002765 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002766 int uid = intent.getIntExtra(
2767 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2768 String authTokenType = intent.getStringExtra(
2769 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002770 final String titleAndSubtitle =
2771 mContext.getString(R.string.permission_request_notification_with_subtitle,
2772 account.name);
2773 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002774 String title = titleAndSubtitle;
2775 String subtitle = "";
2776 if (index > 0) {
2777 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002778 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002779 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002780 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002781 Context contextForUser = getContextForUser(user);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002782 Notification n = new Notification.Builder(contextForUser)
2783 .setSmallIcon(android.R.drawable.stat_sys_warning)
2784 .setWhen(0)
2785 .setColor(contextForUser.getColor(
2786 com.android.internal.R.color.system_notification_accent_color))
2787 .setContentTitle(title)
2788 .setContentText(subtitle)
2789 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2790 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2791 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002792 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002793 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002794 }
2795
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002796 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2797 int uid, AccountAuthenticatorResponse response, String authTokenType,
2798 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002799
2800 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002801
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002802 if (startInNewTask) {
2803 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2804 // Since it was set in Eclair+ we can't change it without breaking apps using
2805 // the intent from a non-Activity context. This is the default behavior.
2806 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2807 }
2808 intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
2809 authTokenType, uid) + (packageName != null ? packageName : "")));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002810 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002811 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2812 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002813 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002814
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002815 return intent;
2816 }
2817
2818 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2819 int uid) {
2820 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002821 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002822 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002823 final Pair<Pair<Account, String>, Integer> key =
2824 new Pair<Pair<Account, String>, Integer>(
2825 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002826 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002827 if (id == null) {
2828 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002829 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002830 }
2831 }
2832 return id;
2833 }
2834
Amith Yamasani04e0d262012-02-14 11:50:53 -08002835 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002836 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002837 synchronized (accounts.signinRequiredNotificationIds) {
2838 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002839 if (id == null) {
2840 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002841 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002842 }
2843 }
2844 return id;
2845 }
2846
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002847 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002848 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002849 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002850 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002851 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002852 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2853 Log.v(TAG, "addAccount: accountType " + accountType
2854 + ", response " + response
2855 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002856 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002857 + ", expectActivityLaunch " + expectActivityLaunch
2858 + ", caller's uid " + Binder.getCallingUid()
2859 + ", pid " + Binder.getCallingPid());
2860 }
Fred Quintana382601f2010-03-25 12:25:10 -07002861 if (response == null) throw new IllegalArgumentException("response is null");
2862 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002863
Amith Yamasani71e6c692013-03-24 17:39:28 -07002864 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002865 final int uid = Binder.getCallingUid();
2866 final int userId = UserHandle.getUserId(uid);
2867 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002868 try {
2869 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2870 "User is not allowed to add an account!");
2871 } catch (RemoteException re) {
2872 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002873 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002874 return;
2875 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002876 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002877 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002878 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2879 "User cannot modify accounts of this type (policy).");
2880 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002881 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002882 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2883 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002884 return;
2885 }
2886
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002887 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002888 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2889 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2890 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2891
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002892 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002893 long identityToken = clearCallingIdentity();
2894 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002895 UserAccounts accounts = getUserAccounts(usrId);
2896 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002897 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2898 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002899 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002900 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002901 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002902 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002903 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07002904 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07002905 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002906 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002907
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002908 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002909 protected String toDebugString(long now) {
2910 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07002911 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002912 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002913 }
2914 }.bind();
2915 } finally {
2916 restoreCallingIdentity(identityToken);
2917 }
Fred Quintana60307342009-03-24 22:48:12 -07002918 }
2919
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002920 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002921 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
2922 final String authTokenType, final String[] requiredFeatures,
2923 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002924 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002925 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002926 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2927 Log.v(TAG, "addAccount: accountType " + accountType
2928 + ", response " + response
2929 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002930 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002931 + ", expectActivityLaunch " + expectActivityLaunch
2932 + ", caller's uid " + Binder.getCallingUid()
2933 + ", pid " + Binder.getCallingPid()
2934 + ", for user id " + userId);
2935 }
2936 if (response == null) throw new IllegalArgumentException("response is null");
2937 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002938 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002939 if (isCrossUser(callingUid, userId)) {
2940 throw new SecurityException(
2941 String.format(
2942 "User %s trying to add account for %s" ,
2943 UserHandle.getCallingUserId(),
2944 userId));
2945 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002946
2947 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002948 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002949 try {
2950 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2951 "User is not allowed to add an account!");
2952 } catch (RemoteException re) {
2953 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002954 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002955 return;
2956 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002957 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002958 try {
2959 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2960 "User cannot modify accounts of this type (policy).");
2961 } catch (RemoteException re) {
2962 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002963 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2964 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002965 return;
2966 }
2967
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002968 final int pid = Binder.getCallingPid();
2969 final int uid = Binder.getCallingUid();
2970 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2971 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2972 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2973
2974 long identityToken = clearCallingIdentity();
2975 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002976 UserAccounts accounts = getUserAccounts(userId);
2977 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002978 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2979 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002980 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002981 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002982 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002983 @Override
2984 public void run() throws RemoteException {
2985 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
2986 options);
2987 }
2988
2989 @Override
2990 protected String toDebugString(long now) {
2991 return super.toDebugString(now) + ", addAccount"
2992 + ", accountType " + accountType
2993 + ", requiredFeatures "
2994 + (requiredFeatures != null
2995 ? TextUtils.join(",", requiredFeatures)
2996 : null);
2997 }
2998 }.bind();
2999 } finally {
3000 restoreCallingIdentity(identityToken);
3001 }
3002 }
3003
Sandra Kwan78812282015-11-04 11:19:47 -08003004 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003005 public void startAddAccountSession(
3006 final IAccountManagerResponse response,
3007 final String accountType,
3008 final String authTokenType,
3009 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003010 final boolean expectActivityLaunch,
3011 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003012 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003013 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3014 Log.v(TAG,
3015 "startAddAccountSession: accountType " + accountType
3016 + ", response " + response
3017 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003018 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003019 + ", expectActivityLaunch " + expectActivityLaunch
3020 + ", caller's uid " + Binder.getCallingUid()
3021 + ", pid " + Binder.getCallingPid());
3022 }
3023 if (response == null) {
3024 throw new IllegalArgumentException("response is null");
3025 }
3026 if (accountType == null) {
3027 throw new IllegalArgumentException("accountType is null");
3028 }
3029
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003030 final int uid = Binder.getCallingUid();
3031 final int userId = UserHandle.getUserId(uid);
3032 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003033 try {
3034 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3035 "User is not allowed to add an account!");
3036 } catch (RemoteException re) {
3037 }
3038 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3039 return;
3040 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003041 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003042 try {
3043 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3044 "User cannot modify accounts of this type (policy).");
3045 } catch (RemoteException re) {
3046 }
3047 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3048 userId);
3049 return;
3050 }
Sandra Kwan78812282015-11-04 11:19:47 -08003051 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003052 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3053 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3054 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3055
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003056 // Check to see if the Password should be included to the caller.
3057 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3058 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003059 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003060
Sandra Kwan78812282015-11-04 11:19:47 -08003061 long identityToken = clearCallingIdentity();
3062 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003063 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003064 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3065 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003066 new StartAccountSession(
3067 accounts,
3068 response,
3069 accountType,
3070 expectActivityLaunch,
3071 null /* accountName */,
3072 false /* authDetailsRequired */,
3073 true /* updateLastAuthenticationTime */,
3074 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003075 @Override
3076 public void run() throws RemoteException {
3077 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3078 requiredFeatures, options);
3079 }
3080
3081 @Override
3082 protected String toDebugString(long now) {
3083 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3084 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3085 + accountType + ", requiredFeatures "
3086 + (requiredFeatures != null ? requiredFeaturesStr : null);
3087 }
3088 }.bind();
3089 } finally {
3090 restoreCallingIdentity(identityToken);
3091 }
3092 }
3093
3094 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3095 private abstract class StartAccountSession extends Session {
3096
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003097 private final boolean mIsPasswordForwardingAllowed;
3098
3099 public StartAccountSession(
3100 UserAccounts accounts,
3101 IAccountManagerResponse response,
3102 String accountType,
3103 boolean expectActivityLaunch,
3104 String accountName,
3105 boolean authDetailsRequired,
3106 boolean updateLastAuthenticationTime,
3107 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003108 super(accounts, response, accountType, expectActivityLaunch,
3109 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3110 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003111 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003112 }
3113
3114 @Override
3115 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003116 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003117 mNumResults++;
3118 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003119 if (result != null
3120 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003121 checkKeyIntent(
3122 Binder.getCallingUid(),
3123 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003124 }
Sandra Kwan78812282015-11-04 11:19:47 -08003125 IAccountManagerResponse response;
3126 if (mExpectActivityLaunch && result != null
3127 && result.containsKey(AccountManager.KEY_INTENT)) {
3128 response = mResponse;
3129 } else {
3130 response = getResponseAndClose();
3131 }
3132 if (response == null) {
3133 return;
3134 }
3135 if (result == null) {
3136 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3137 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3138 + response);
3139 }
3140 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3141 "null bundle returned");
3142 return;
3143 }
3144
3145 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3146 // All AccountManager error codes are greater
3147 // than 0
3148 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3149 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3150 return;
3151 }
3152
Hongming Jin368aa192016-07-29 14:29:54 -07003153 // Omit passwords if the caller isn't permitted to see them.
3154 if (!mIsPasswordForwardingAllowed) {
3155 result.remove(AccountManager.KEY_PASSWORD);
3156 }
3157
Sandra Kwan78812282015-11-04 11:19:47 -08003158 // Strip auth token from result.
3159 result.remove(AccountManager.KEY_AUTHTOKEN);
3160
3161 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3162 Log.v(TAG,
3163 getClass().getSimpleName() + " calling onResult() on response " + response);
3164 }
3165
3166 // Get the session bundle created by authenticator. The
3167 // bundle contains data necessary for finishing the session
3168 // later. The session bundle will be encrypted here and
3169 // decrypted later when trying to finish the session.
3170 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3171 if (sessionBundle != null) {
3172 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3173 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003174 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003175 Log.w(TAG, "Account type in session bundle doesn't match request.");
3176 }
3177 // Add accountType info to session bundle. This will
3178 // override any value set by authenticator.
3179 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3180
3181 // Encrypt session bundle before returning to caller.
3182 try {
3183 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3184 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3185 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3186 } catch (GeneralSecurityException e) {
3187 if (Log.isLoggable(TAG, Log.DEBUG)) {
3188 Log.v(TAG, "Failed to encrypt session bundle!", e);
3189 }
3190 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3191 "failed to encrypt session bundle");
3192 return;
3193 }
3194 }
3195
3196 sendResponse(response, result);
3197 }
3198 }
3199
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003200 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003201 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003202 @NonNull Bundle sessionBundle,
3203 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003204 Bundle appInfo,
3205 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003206 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003207 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003208 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3209 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003210 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003211 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003212 + ", caller's uid " + callingUid
3213 + ", caller's user id " + UserHandle.getCallingUserId()
3214 + ", pid " + Binder.getCallingPid()
3215 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003216 }
3217 if (response == null) {
3218 throw new IllegalArgumentException("response is null");
3219 }
3220
3221 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3222 // Account type is added to it before encryption.
3223 if (sessionBundle == null || sessionBundle.size() == 0) {
3224 throw new IllegalArgumentException("sessionBundle is empty");
3225 }
3226
Dmitry Dementyev52745472016-12-02 10:27:45 -08003227 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003228 if (isCrossUser(callingUid, userId)) {
3229 throw new SecurityException(
3230 String.format(
3231 "User %s trying to finish session for %s without cross user permission",
3232 UserHandle.getCallingUserId(),
3233 userId));
3234 }
3235
Sandra Kwan0b84b452016-01-20 15:25:42 -08003236 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003237 sendErrorResponse(response,
3238 AccountManager.ERROR_CODE_USER_RESTRICTED,
3239 "User is not allowed to add an account!");
3240 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3241 return;
3242 }
3243
3244 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003245 final Bundle decryptedBundle;
3246 final String accountType;
3247 // First decrypt session bundle to get account type for checking permission.
3248 try {
3249 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3250 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3251 if (decryptedBundle == null) {
3252 sendErrorResponse(
3253 response,
3254 AccountManager.ERROR_CODE_BAD_REQUEST,
3255 "failed to decrypt session bundle");
3256 return;
3257 }
3258 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3259 // Account type cannot be null. This should not happen if session bundle was created
3260 // properly by #StartAccountSession.
3261 if (TextUtils.isEmpty(accountType)) {
3262 sendErrorResponse(
3263 response,
3264 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3265 "accountType is empty");
3266 return;
3267 }
3268
3269 // If by any chances, decryptedBundle contains colliding keys with
3270 // system info
3271 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3272 // update credentials flow, we should replace with the new values of the current call.
3273 if (appInfo != null) {
3274 decryptedBundle.putAll(appInfo);
3275 }
3276
3277 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003278 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003279 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3280 } catch (GeneralSecurityException e) {
3281 if (Log.isLoggable(TAG, Log.DEBUG)) {
3282 Log.v(TAG, "Failed to decrypt session bundle!", e);
3283 }
3284 sendErrorResponse(
3285 response,
3286 AccountManager.ERROR_CODE_BAD_REQUEST,
3287 "failed to decrypt session bundle");
3288 return;
3289 }
3290
Sandra Kwan0b84b452016-01-20 15:25:42 -08003291 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003292 sendErrorResponse(
3293 response,
3294 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3295 "User cannot modify accounts of this type (policy).");
3296 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3297 userId);
3298 return;
3299 }
3300
3301 long identityToken = clearCallingIdentity();
3302 try {
3303 UserAccounts accounts = getUserAccounts(userId);
3304 logRecordWithUid(
3305 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003306 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3307 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003308 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003309 new Session(
3310 accounts,
3311 response,
3312 accountType,
3313 expectActivityLaunch,
3314 true /* stripAuthTokenFromResult */,
3315 null /* accountName */,
3316 false /* authDetailsRequired */,
3317 true /* updateLastAuthenticationTime */) {
3318 @Override
3319 public void run() throws RemoteException {
3320 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3321 }
3322
3323 @Override
3324 protected String toDebugString(long now) {
3325 return super.toDebugString(now)
3326 + ", finishSession"
3327 + ", accountType " + accountType;
3328 }
3329 }.bind();
3330 } finally {
3331 restoreCallingIdentity(identityToken);
3332 }
3333 }
3334
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003335 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003336 final DevicePolicyManagerInternal dpmi =
3337 LocalServices.getService(DevicePolicyManagerInternal.class);
3338 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003339 if (dpmi == null) {
3340 intent = getDefaultCantAddAccountIntent(errorCode);
3341 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003342 intent = dpmi.createUserRestrictionSupportIntent(userId,
3343 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3344 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3345 intent = dpmi.createShowAdminSupportIntent(userId, false);
3346 }
3347 if (intent == null) {
3348 intent = getDefaultCantAddAccountIntent(errorCode);
3349 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003350 long identityToken = clearCallingIdentity();
3351 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003352 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003353 } finally {
3354 restoreCallingIdentity(identityToken);
3355 }
3356 }
3357
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003358 /**
3359 * Called when we don't know precisely who is preventing us from adding an account.
3360 */
3361 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3362 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3363 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3364 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3365 return cantAddAccount;
3366 }
3367
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003368 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003369 public void confirmCredentialsAsUser(
3370 IAccountManagerResponse response,
3371 final Account account,
3372 final Bundle options,
3373 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003374 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003375 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003376 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003377 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3378 Log.v(TAG, "confirmCredentials: " + account
3379 + ", response " + response
3380 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003381 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003382 + ", pid " + Binder.getCallingPid());
3383 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003384 // Only allow the system process to read accounts of other users
3385 if (isCrossUser(callingUid, userId)) {
3386 throw new SecurityException(
3387 String.format(
3388 "User %s trying to confirm account credentials for %s" ,
3389 UserHandle.getCallingUserId(),
3390 userId));
3391 }
Fred Quintana382601f2010-03-25 12:25:10 -07003392 if (response == null) throw new IllegalArgumentException("response is null");
3393 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003394 long identityToken = clearCallingIdentity();
3395 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003396 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003397 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003398 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003399 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003400 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003401 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003402 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003403 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003404 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003405 protected String toDebugString(long now) {
3406 return super.toDebugString(now) + ", confirmCredentials"
3407 + ", " + account;
3408 }
3409 }.bind();
3410 } finally {
3411 restoreCallingIdentity(identityToken);
3412 }
Fred Quintana60307342009-03-24 22:48:12 -07003413 }
3414
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003415 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003416 public void updateCredentials(IAccountManagerResponse response, final Account account,
3417 final String authTokenType, final boolean expectActivityLaunch,
3418 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003419 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003420 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3421 Log.v(TAG, "updateCredentials: " + account
3422 + ", response " + response
3423 + ", authTokenType " + authTokenType
3424 + ", expectActivityLaunch " + expectActivityLaunch
3425 + ", caller's uid " + Binder.getCallingUid()
3426 + ", pid " + Binder.getCallingPid());
3427 }
Fred Quintana382601f2010-03-25 12:25:10 -07003428 if (response == null) throw new IllegalArgumentException("response is null");
3429 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003430 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003431 long identityToken = clearCallingIdentity();
3432 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003433 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003434 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003435 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003436 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003437 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003438 public void run() throws RemoteException {
3439 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3440 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003441 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003442 protected String toDebugString(long now) {
3443 if (loginOptions != null) loginOptions.keySet();
3444 return super.toDebugString(now) + ", updateCredentials"
3445 + ", " + account
3446 + ", authTokenType " + authTokenType
3447 + ", loginOptions " + loginOptions;
3448 }
3449 }.bind();
3450 } finally {
3451 restoreCallingIdentity(identityToken);
3452 }
Fred Quintana60307342009-03-24 22:48:12 -07003453 }
3454
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003455 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003456 public void startUpdateCredentialsSession(
3457 IAccountManagerResponse response,
3458 final Account account,
3459 final String authTokenType,
3460 final boolean expectActivityLaunch,
3461 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003462 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003463 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3464 Log.v(TAG,
3465 "startUpdateCredentialsSession: " + account + ", response " + response
3466 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3467 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3468 + ", pid " + Binder.getCallingPid());
3469 }
3470 if (response == null) {
3471 throw new IllegalArgumentException("response is null");
3472 }
3473 if (account == null) {
3474 throw new IllegalArgumentException("account is null");
3475 }
Sandra Kwana578d112015-12-16 16:01:43 -08003476
3477 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003478 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003479
3480 // Check to see if the Password should be included to the caller.
3481 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3482 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003483 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003484
Sandra Kwane68c37e2015-11-12 17:11:49 -08003485 long identityToken = clearCallingIdentity();
3486 try {
3487 UserAccounts accounts = getUserAccounts(userId);
3488 new StartAccountSession(
3489 accounts,
3490 response,
3491 account.type,
3492 expectActivityLaunch,
3493 account.name,
3494 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003495 true /* updateLastCredentialTime */,
3496 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003497 @Override
3498 public void run() throws RemoteException {
3499 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3500 loginOptions);
3501 }
3502
3503 @Override
3504 protected String toDebugString(long now) {
3505 if (loginOptions != null)
3506 loginOptions.keySet();
3507 return super.toDebugString(now)
3508 + ", startUpdateCredentialsSession"
3509 + ", " + account
3510 + ", authTokenType " + authTokenType
3511 + ", loginOptions " + loginOptions;
3512 }
3513 }.bind();
3514 } finally {
3515 restoreCallingIdentity(identityToken);
3516 }
3517 }
3518
3519 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003520 public void isCredentialsUpdateSuggested(
3521 IAccountManagerResponse response,
3522 final Account account,
3523 final String statusToken) {
3524 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3525 Log.v(TAG,
3526 "isCredentialsUpdateSuggested: " + account + ", response " + response
3527 + ", caller's uid " + Binder.getCallingUid()
3528 + ", pid " + Binder.getCallingPid());
3529 }
3530 if (response == null) {
3531 throw new IllegalArgumentException("response is null");
3532 }
3533 if (account == null) {
3534 throw new IllegalArgumentException("account is null");
3535 }
3536 if (TextUtils.isEmpty(statusToken)) {
3537 throw new IllegalArgumentException("status token is empty");
3538 }
3539
Sandra Kwan390c9d22016-01-12 14:13:37 -08003540 int usrId = UserHandle.getCallingUserId();
3541 long identityToken = clearCallingIdentity();
3542 try {
3543 UserAccounts accounts = getUserAccounts(usrId);
3544 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3545 false /* stripAuthTokenFromResult */, account.name,
3546 false /* authDetailsRequired */) {
3547 @Override
3548 protected String toDebugString(long now) {
3549 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3550 + ", " + account;
3551 }
3552
3553 @Override
3554 public void run() throws RemoteException {
3555 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3556 }
3557
3558 @Override
3559 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003560 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003561 IAccountManagerResponse response = getResponseAndClose();
3562 if (response == null) {
3563 return;
3564 }
3565
3566 if (result == null) {
3567 sendErrorResponse(
3568 response,
3569 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3570 "null bundle");
3571 return;
3572 }
3573
3574 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3575 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3576 + response);
3577 }
3578 // Check to see if an error occurred. We know if an error occurred because all
3579 // error codes are greater than 0.
3580 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3581 sendErrorResponse(response,
3582 result.getInt(AccountManager.KEY_ERROR_CODE),
3583 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3584 return;
3585 }
3586 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3587 sendErrorResponse(
3588 response,
3589 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3590 "no result in response");
3591 return;
3592 }
3593 final Bundle newResult = new Bundle();
3594 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3595 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3596 sendResponse(response, newResult);
3597 }
3598 }.bind();
3599 } finally {
3600 restoreCallingIdentity(identityToken);
3601 }
3602 }
3603
3604 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003605 public void editProperties(IAccountManagerResponse response, final String accountType,
3606 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003607 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003608 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3609 Log.v(TAG, "editProperties: accountType " + accountType
3610 + ", response " + response
3611 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003612 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003613 + ", pid " + Binder.getCallingPid());
3614 }
Fred Quintana382601f2010-03-25 12:25:10 -07003615 if (response == null) throw new IllegalArgumentException("response is null");
3616 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003617 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003618 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3619 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003620 String msg = String.format(
3621 "uid %s cannot edit authenticator properites for account type: %s",
3622 callingUid,
3623 accountType);
3624 throw new SecurityException(msg);
3625 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003626 long identityToken = clearCallingIdentity();
3627 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003628 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003629 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003630 true /* stripAuthTokenFromResult */, null /* accountName */,
3631 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003632 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003633 public void run() throws RemoteException {
3634 mAuthenticator.editProperties(this, mAccountType);
3635 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003636 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003637 protected String toDebugString(long now) {
3638 return super.toDebugString(now) + ", editProperties"
3639 + ", accountType " + accountType;
3640 }
3641 }.bind();
3642 } finally {
3643 restoreCallingIdentity(identityToken);
3644 }
Fred Quintana60307342009-03-24 22:48:12 -07003645 }
3646
Amith Yamasani12747872015-12-07 14:19:49 -08003647 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003648 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3649 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003650 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003651 throw new SecurityException("Can be called only by system UID");
3652 }
3653 Preconditions.checkNotNull(account, "account cannot be null");
3654 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3655 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3656
3657 final int userId = userHandle.getIdentifier();
3658
3659 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3660
3661 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003662 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003663 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003664 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003665 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003666 return false;
3667 }
3668 }
3669
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003670 // Returns package with oldest target SDK for given UID.
3671 private String getPackageNameForUid(int uid) {
3672 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3673 if (ArrayUtils.isEmpty(packageNames)) {
3674 return null;
3675 }
3676 // For app op checks related to permissions all packages in the UID
3677 // have the same app op state, so doesn't matter which one we pick.
3678 // Update: due to visibility changes we want to use package with oldest target SDK,
3679
3680 String packageName = packageNames[0];
3681 int oldestVersion = Integer.MAX_VALUE;
3682 for (String name : packageNames) {
3683 try {
3684 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3685 if (applicationInfo != null) {
3686 int version = applicationInfo.targetSdkVersion;
3687 if (version < oldestVersion) {
3688 oldestVersion = version;
3689 packageName = name;
3690 }
3691 }
3692 } catch (NameNotFoundException e) {
3693 // skip
3694 }
3695 }
3696 return packageName;
3697 }
3698
Svet Ganovf6d424f12016-09-20 20:18:53 -07003699 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3700 int uid) {
3701 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003702 packageName = getPackageNameForUid(uid);
3703 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003704 return false;
3705 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003706 }
3707
3708 // Use null token which means any token. Having a token means the package
3709 // is trusted by the authenticator, hence it is fine to access the account.
3710 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3711 return true;
3712 }
3713 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003714 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003715
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003716 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003717 getUserAccounts(UserHandle.getUserId(uid)));
3718 return (visibility == AccountManager.VISIBILITY_VISIBLE
3719 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003720 }
3721
3722 @Override
3723 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3724 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003725 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003726 throw new SecurityException("Can be called only by system UID");
3727 }
3728
3729 Preconditions.checkNotNull(account, "account cannot be null");
3730 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3731 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3732
3733 final int userId = userHandle.getIdentifier();
3734
3735 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3736
3737 final int uid;
3738 try {
3739 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3740 } catch (NameNotFoundException e) {
3741 Slog.e(TAG, "Unknown package " + packageName);
3742 return null;
3743 }
3744
3745 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3746
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003747 final long identity = Binder.clearCallingIdentity();
3748 try {
3749 return PendingIntent.getActivityAsUser(
3750 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3751 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3752 null, new UserHandle(userId)).getIntentSender();
3753 } finally {
3754 Binder.restoreCallingIdentity(identity);
3755 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003756 }
3757
3758 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3759 int uid, RemoteCallback callback) {
3760 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3761 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3762 @Override
3763 public void onResult(Bundle value) throws RemoteException {
3764 handleAuthenticatorResponse(true);
3765 }
3766
3767 @Override
3768 public void onRequestContinued() {
3769 /* ignore */
3770 }
3771
3772 @Override
3773 public void onError(int errorCode, String errorMessage) throws RemoteException {
3774 handleAuthenticatorResponse(false);
3775 }
3776
3777 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3778 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003779 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003780 UserHandle.getUserHandleForUid(uid));
3781 if (callback != null) {
3782 Bundle result = new Bundle();
3783 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3784 callback.sendResult(result);
3785 }
3786 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003787 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003788 }
3789
3790 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003791 public boolean someUserHasAccount(@NonNull final Account account) {
3792 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3793 throw new SecurityException("Only system can check for accounts across users");
3794 }
3795 final long token = Binder.clearCallingIdentity();
3796 try {
3797 AccountAndUser[] allAccounts = getAllAccounts();
3798 for (int i = allAccounts.length - 1; i >= 0; i--) {
3799 if (allAccounts[i].account.equals(account)) {
3800 return true;
3801 }
3802 }
3803 return false;
3804 } finally {
3805 Binder.restoreCallingIdentity(token);
3806 }
3807 }
3808
Fred Quintana33269202009-04-20 16:05:10 -07003809 private class GetAccountsByTypeAndFeatureSession extends Session {
3810 private final String[] mFeatures;
3811 private volatile Account[] mAccountsOfType = null;
3812 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3813 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003814 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003815 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003816
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003817 public GetAccountsByTypeAndFeatureSession(
3818 UserAccounts accounts,
3819 IAccountManagerResponse response,
3820 String type,
3821 String[] features,
3822 int callingUid,
3823 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003824 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003825 true /* stripAuthTokenFromResult */, null /* accountName */,
3826 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003827 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003828 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003829 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003830 }
3831
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003832 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003833 public void run() throws RemoteException {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003834 synchronized (mAccounts.cacheLock) {
Amith Yamasani27db4682013-03-30 17:07:47 -07003835 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003836 mPackageName, false /* include managed not visible*/);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003837 }
Fred Quintana33269202009-04-20 16:05:10 -07003838 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003839 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003840 mCurrentAccount = 0;
3841
3842 checkAccount();
3843 }
3844
3845 public void checkAccount() {
3846 if (mCurrentAccount >= mAccountsOfType.length) {
3847 sendResult();
3848 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003849 }
Fred Quintana33269202009-04-20 16:05:10 -07003850
Fred Quintana29e94b82010-03-10 12:11:51 -08003851 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3852 if (accountAuthenticator == null) {
3853 // It is possible that the authenticator has died, which is indicated by
3854 // mAuthenticator being set to null. If this happens then just abort.
3855 // There is no need to send back a result or error in this case since
3856 // that already happened when mAuthenticator was cleared.
3857 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3858 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3859 + " connected to the authenticator, " + toDebugString());
3860 }
3861 return;
3862 }
Fred Quintana33269202009-04-20 16:05:10 -07003863 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003864 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003865 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003866 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003867 }
3868 }
3869
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003870 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003871 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003872 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003873 mNumResults++;
3874 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003875 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003876 return;
3877 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003878 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003879 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3880 }
3881 mCurrentAccount++;
3882 checkAccount();
3883 }
3884
3885 public void sendResult() {
3886 IAccountManagerResponse response = getResponseAndClose();
3887 if (response != null) {
3888 try {
3889 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3890 for (int i = 0; i < accounts.length; i++) {
3891 accounts[i] = mAccountsWithFeatures.get(i);
3892 }
Fred Quintana56285a62010-12-02 14:20:51 -08003893 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3894 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3895 + response);
3896 }
Fred Quintana33269202009-04-20 16:05:10 -07003897 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003898 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07003899 response.onResult(result);
3900 } catch (RemoteException e) {
3901 // if the caller is dead then there is no one to care about remote exceptions
3902 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3903 Log.v(TAG, "failure while notifying response", e);
3904 }
3905 }
3906 }
3907 }
3908
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003909 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003910 protected String toDebugString(long now) {
3911 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
3912 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
3913 }
3914 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07003915
Amith Yamasani04e0d262012-02-14 11:50:53 -08003916 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003917 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08003918 * @hide
3919 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003920 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07003921 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003922 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003923 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07003924 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
3925 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003926 if (visibleAccountTypes.isEmpty()) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003927 return new Account[0];
3928 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003929 long identityToken = clearCallingIdentity();
3930 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003931 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003932 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003933 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003934 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003935 opPackageName,
3936 visibleAccountTypes,
3937 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003938 } finally {
3939 restoreCallingIdentity(identityToken);
3940 }
3941 }
3942
Amith Yamasanif29f2362012-04-05 18:29:52 -07003943 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003944 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003945 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07003946 * @hide
3947 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003948 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003949 public AccountAndUser[] getRunningAccounts() {
3950 final int[] runningUserIds;
3951 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08003952 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003953 } catch (RemoteException e) {
3954 // Running in system_server; should never happen
3955 throw new RuntimeException(e);
3956 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003957 return getAccounts(runningUserIds);
3958 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07003959
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003960 /**
3961 * Returns accounts for all users, ignores visibility values.
3962 *
3963 * @hide
3964 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003965 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003966 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07003967 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003968 final int[] userIds = new int[users.size()];
3969 for (int i = 0; i < userIds.length; i++) {
3970 userIds[i] = users.get(i).id;
3971 }
3972 return getAccounts(userIds);
3973 }
3974
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003975 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003976 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003977 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07003978 for (int userId : userIds) {
3979 UserAccounts userAccounts = getUserAccounts(userId);
3980 if (userAccounts == null) continue;
3981 synchronized (userAccounts.cacheLock) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003982 Account[] accounts = getAccountsFromCacheLocked(
3983 userAccounts,
3984 null /* type */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003985 Binder.getCallingUid(),
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003986 null /* packageName */,
3987 false /* include managed not visible*/);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07003988 for (int a = 0; a < accounts.length; a++) {
3989 runningAccounts.add(new AccountAndUser(accounts[a], userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07003990 }
3991 }
3992 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003993
3994 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
3995 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07003996 }
3997
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003998 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003999 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004000 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004001 int callingUid = Binder.getCallingUid();
4002 mAppOpsManager.checkPackage(callingUid, opPackageName);
4003 return getAccountsAsUser(type, userId, opPackageName /* callingPackage */, -1,
4004 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004005 }
4006
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004007 @NonNull
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004008 private Account[] getAccountsAsUser(
4009 String type,
4010 int userId,
4011 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004012 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004013 String opPackageName,
4014 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004015 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004016 // Only allow the system process to read accounts of other users
4017 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004018 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004019 && mContext.checkCallingOrSelfPermission(
4020 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4021 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004022 throw new SecurityException("User " + UserHandle.getCallingUserId()
4023 + " trying to get account for " + userId);
4024 }
4025
Fred Quintana56285a62010-12-02 14:20:51 -08004026 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4027 Log.v(TAG, "getAccounts: accountType " + type
4028 + ", caller's uid " + Binder.getCallingUid()
4029 + ", pid " + Binder.getCallingPid());
4030 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004031
4032 // If the original calling app was using account choosing activity
4033 // provided by the framework or authenticator we'll passing in
4034 // the original caller's uid here, which is what should be used for filtering.
4035 List<String> managedTypes =
4036 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4037 if (packageUid != -1 &&
4038 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4039 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004040 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004041 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004042 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004043 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4044 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004045 if (visibleAccountTypes.isEmpty()
4046 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004047 return new Account[]{};
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004048 } else if (visibleAccountTypes.contains(type)) {
4049 // Prune the list down to just the requested type.
4050 visibleAccountTypes = new ArrayList<>();
4051 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004052 } // else aggregate all the visible accounts (it won't matter if the
4053 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004054
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004055 long identityToken = clearCallingIdentity();
4056 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004057 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004058 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004059 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004060 callingUid,
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00004061 callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004062 visibleAccountTypes,
4063 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004064 } finally {
4065 restoreCallingIdentity(identityToken);
4066 }
4067 }
4068
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004069 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004070 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004071 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004072 int callingUid,
4073 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004074 List<String> visibleAccountTypes,
4075 boolean includeUserManagedNotVisible) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004076 synchronized (userAccounts.cacheLock) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004077 ArrayList<Account> visibleAccounts = new ArrayList<>();
4078 for (String visibleType : visibleAccountTypes) {
4079 Account[] accountsForType = getAccountsFromCacheLocked(
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004080 userAccounts, visibleType, callingUid, callingPackage,
4081 includeUserManagedNotVisible);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004082 if (accountsForType != null) {
4083 visibleAccounts.addAll(Arrays.asList(accountsForType));
4084 }
4085 }
4086 Account[] result = new Account[visibleAccounts.size()];
4087 for (int i = 0; i < visibleAccounts.size(); i++) {
4088 result[i] = visibleAccounts.get(i);
4089 }
4090 return result;
4091 }
4092 }
4093
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004094 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004095 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4096 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004097 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004098 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004099 for (Account account : accounts) {
4100 addSharedAccountAsUser(account, userId);
4101 }
4102 }
4103
4104 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004105 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004106 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004107 accounts.accountsDb.deleteSharedAccount(account);
4108 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004109 if (accountId < 0) {
4110 Log.w(TAG, "insertAccountIntoDatabase: " + account
4111 + ", skipping the DB insert failed");
4112 return false;
4113 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004114 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4115 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004116 return true;
4117 }
4118
4119 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004120 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4121 userId = handleIncomingUser(userId);
4122 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004123 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4124 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004125 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004126 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004127 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004128 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004129 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004130 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004131 }
4132 return r > 0;
4133 }
4134
4135 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004136 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004137 return removeSharedAccountAsUser(account, userId, getCallingUid());
4138 }
4139
4140 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004141 userId = handleIncomingUser(userId);
4142 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004143 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4144 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004145 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004146 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004147 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004148 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004149 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004150 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004151 }
4152
4153 @Override
4154 public Account[] getSharedAccountsAsUser(int userId) {
4155 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004156 UserAccounts accounts = getUserAccounts(userId);
4157 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004158 Account[] accountArray = new Account[accountList.size()];
4159 accountList.toArray(accountArray);
4160 return accountArray;
4161 }
4162
4163 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004164 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004165 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004166 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004167 }
4168
Amith Yamasani27db4682013-03-30 17:07:47 -07004169 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004170 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004171 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004172 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004173 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004174 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004175 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4176 + callingUid + " with uid=" + uid);
4177 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004178 return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004179 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004180 }
4181
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004182 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004183 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004184 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4185 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004186 int callingUid = Binder.getCallingUid();
4187 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004188 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004189 int packageUid = -1;
4190 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004191 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4192 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004193 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
4194 return new Account[0];
4195 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004196 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4197 && !isAccountManagedByCaller(type, callingUid, userId)) {
4198 return new Account[0];
4199 }
4200
4201 return getAccountsAsUser(type, userId,
4202 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004203 }
4204
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004205 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004206 public void getAccountsByFeatures(
4207 IAccountManagerResponse response,
4208 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004209 String[] features,
4210 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004211 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004212 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004213 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4214 Log.v(TAG, "getAccounts: accountType " + type
4215 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004216 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004217 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004218 + ", pid " + Binder.getCallingPid());
4219 }
Fred Quintana382601f2010-03-25 12:25:10 -07004220 if (response == null) throw new IllegalArgumentException("response is null");
4221 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004222 int userId = UserHandle.getCallingUserId();
4223
Svetoslavf3f02ac2015-09-08 14:36:35 -07004224 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4225 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004226 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004227 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004228 // Need to return just the accounts that are from matching signatures.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004229 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);
4230 try {
4231 response.onResult(result);
4232 } catch (RemoteException e) {
4233 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4234 }
4235 return;
4236 }
Fred Quintana33269202009-04-20 16:05:10 -07004237 long identityToken = clearCallingIdentity();
4238 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004239 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004240 if (features == null || features.length == 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004241 Account[] accounts;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004242 synchronized (userAccounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004243 accounts = getAccountsFromCacheLocked(
4244 userAccounts, type, callingUid, opPackageName, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004245 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004246 Bundle result = new Bundle();
4247 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4248 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004249 return;
4250 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004251 new GetAccountsByTypeAndFeatureSession(
4252 userAccounts,
4253 response,
4254 type,
4255 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004256 callingUid,
4257 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004258 } finally {
4259 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004260 }
4261 }
4262
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004263 @Override
4264 public void onAccountAccessed(String token) throws RemoteException {
4265 final int uid = Binder.getCallingUid();
4266 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4267 return;
4268 }
4269 final int userId = UserHandle.getCallingUserId();
4270 final long identity = Binder.clearCallingIdentity();
4271 try {
4272 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4273 if (Objects.equals(account.getAccessId(), token)) {
4274 // An app just accessed the account. At this point it knows about
4275 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004276 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004277 if (!hasAccountAccess(account, null, uid)) {
4278 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4279 uid, true);
4280 }
4281 }
4282 }
4283 } finally {
4284 Binder.restoreCallingIdentity(identity);
4285 }
4286 }
4287
Fred Quintanaa698f422009-04-08 19:14:54 -07004288 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004289 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004290 IAccountManagerResponse mResponse;
4291 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004292 final boolean mExpectActivityLaunch;
4293 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004294 final String mAccountName;
4295 // Indicates if we need to add auth details(like last credential time)
4296 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004297 // If set, we need to update the last authenticated time. This is
4298 // currently
4299 // used on
4300 // successful confirming credentials.
4301 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004302
Fred Quintana33269202009-04-20 16:05:10 -07004303 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004304 private int mNumRequestContinued = 0;
4305 private int mNumErrors = 0;
4306
Fred Quintana60307342009-03-24 22:48:12 -07004307 IAccountAuthenticator mAuthenticator = null;
4308
Fred Quintana8570f742010-02-18 10:32:54 -08004309 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004310 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004311
Amith Yamasani04e0d262012-02-14 11:50:53 -08004312 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004313 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4314 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004315 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4316 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4317 }
4318
4319 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4320 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4321 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004322 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004323 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004324 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004325 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004326 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004327 mResponse = response;
4328 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004329 mExpectActivityLaunch = expectActivityLaunch;
4330 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004331 mAccountName = accountName;
4332 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004333 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004334
Fred Quintanaa698f422009-04-08 19:14:54 -07004335 synchronized (mSessions) {
4336 mSessions.put(toString(), this);
4337 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004338 if (response != null) {
4339 try {
4340 response.asBinder().linkToDeath(this, 0 /* flags */);
4341 } catch (RemoteException e) {
4342 mResponse = null;
4343 binderDied();
4344 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004345 }
Fred Quintana60307342009-03-24 22:48:12 -07004346 }
4347
Fred Quintanaa698f422009-04-08 19:14:54 -07004348 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004349 if (mResponse == null) {
4350 // this session has already been closed
4351 return null;
4352 }
Fred Quintana60307342009-03-24 22:48:12 -07004353 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004354 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004355 return response;
4356 }
4357
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004358 /**
4359 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4360 * security policy.
4361 *
4362 * In particular we want to make sure that the Authenticator doesn't try to trick users
4363 * into launching aribtrary intents on the device via by tricking to click authenticator
4364 * supplied entries in the system Settings app.
4365 */
4366 protected void checkKeyIntent(
4367 int authUid,
4368 Intent intent) throws SecurityException {
4369 long bid = Binder.clearCallingIdentity();
4370 try {
4371 PackageManager pm = mContext.getPackageManager();
4372 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4373 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4374 int targetUid = targetActivityInfo.applicationInfo.uid;
Sandra Kwan0e961a12016-06-30 14:34:01 -07004375 if (!GrantCredentialsPermissionActivity.class.getName().equals(
4376 targetActivityInfo.getClass().getName())
4377 && !CantAddAccountActivity.class
4378 .equals(targetActivityInfo.getClass().getName())
4379 && PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4380 targetUid)) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004381 String pkgName = targetActivityInfo.packageName;
4382 String activityName = targetActivityInfo.name;
4383 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4384 + "does not share a signature with the supplying authenticator (%s).";
4385 throw new SecurityException(
4386 String.format(tmpl, activityName, pkgName, mAccountType));
4387 }
4388 } finally {
4389 Binder.restoreCallingIdentity(bid);
4390 }
4391 }
4392
Fred Quintanaa698f422009-04-08 19:14:54 -07004393 private void close() {
4394 synchronized (mSessions) {
4395 if (mSessions.remove(toString()) == null) {
4396 // the session was already closed, so bail out now
4397 return;
4398 }
4399 }
4400 if (mResponse != null) {
4401 // stop listening for response deaths
4402 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4403
4404 // clear this so that we don't accidentally send any further results
4405 mResponse = null;
4406 }
4407 cancelTimeout();
4408 unbind();
4409 }
4410
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004411 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004412 public void binderDied() {
4413 mResponse = null;
4414 close();
4415 }
4416
4417 protected String toDebugString() {
4418 return toDebugString(SystemClock.elapsedRealtime());
4419 }
4420
4421 protected String toDebugString(long now) {
4422 return "Session: expectLaunch " + mExpectActivityLaunch
4423 + ", connected " + (mAuthenticator != null)
4424 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4425 + "/" + mNumErrors + ")"
4426 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4427 }
4428
Fred Quintana60307342009-03-24 22:48:12 -07004429 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004430 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4431 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4432 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004433 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004434 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004435 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004436 }
4437 }
4438
4439 private void unbind() {
4440 if (mAuthenticator != null) {
4441 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004442 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004443 }
4444 }
4445
Fred Quintana60307342009-03-24 22:48:12 -07004446 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004447 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004448 }
4449
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004450 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004451 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004452 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004453 try {
4454 run();
4455 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004456 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004457 "remote exception");
4458 }
Fred Quintana60307342009-03-24 22:48:12 -07004459 }
4460
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004461 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004462 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004463 mAuthenticator = null;
4464 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004465 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004466 try {
4467 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4468 "disconnected");
4469 } catch (RemoteException e) {
4470 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4471 Log.v(TAG, "Session.onServiceDisconnected: "
4472 + "caught RemoteException while responding", e);
4473 }
4474 }
Fred Quintana60307342009-03-24 22:48:12 -07004475 }
4476 }
4477
Fred Quintanab839afc2009-10-14 15:57:28 -07004478 public abstract void run() throws RemoteException;
4479
Fred Quintana60307342009-03-24 22:48:12 -07004480 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004481 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004482 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004483 try {
4484 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4485 "timeout");
4486 } catch (RemoteException e) {
4487 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4488 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4489 e);
4490 }
4491 }
Fred Quintana60307342009-03-24 22:48:12 -07004492 }
4493 }
4494
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004495 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004496 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004497 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004498 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004499 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004500 if (result != null) {
4501 boolean isSuccessfulConfirmCreds = result.getBoolean(
4502 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004503 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004504 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4505 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004506 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004507 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4508 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004509 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004510 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004511 if (needUpdate || mAuthDetailsRequired) {
4512 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4513 if (needUpdate && accountPresent) {
4514 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4515 }
4516 if (mAuthDetailsRequired) {
4517 long lastAuthenticatedTime = -1;
4518 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004519 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004520 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004521 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004522 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004523 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004524 lastAuthenticatedTime);
4525 }
4526 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004527 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004528 if (result != null
4529 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004530 checkKeyIntent(
4531 Binder.getCallingUid(),
4532 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004533 }
4534 if (result != null
4535 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004536 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4537 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004538 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4539 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004540 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4541 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004542 }
Fred Quintana60307342009-03-24 22:48:12 -07004543 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004544 IAccountManagerResponse response;
4545 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004546 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004547 response = mResponse;
4548 } else {
4549 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004550 }
Fred Quintana60307342009-03-24 22:48:12 -07004551 if (response != null) {
4552 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004553 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004554 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4555 Log.v(TAG, getClass().getSimpleName()
4556 + " calling onError() on response " + response);
4557 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004558 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004559 "null bundle returned");
4560 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004561 if (mStripAuthTokenFromResult) {
4562 result.remove(AccountManager.KEY_AUTHTOKEN);
4563 }
Fred Quintana56285a62010-12-02 14:20:51 -08004564 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4565 Log.v(TAG, getClass().getSimpleName()
4566 + " calling onResult() on response " + response);
4567 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004568 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4569 (intent == null)) {
4570 // All AccountManager error codes are greater than 0
4571 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4572 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4573 } else {
4574 response.onResult(result);
4575 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004576 }
Fred Quintana60307342009-03-24 22:48:12 -07004577 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004578 // if the caller is dead then there is no one to care about remote exceptions
4579 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4580 Log.v(TAG, "failure while notifying response", e);
4581 }
Fred Quintana60307342009-03-24 22:48:12 -07004582 }
4583 }
4584 }
Fred Quintana60307342009-03-24 22:48:12 -07004585
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004586 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004587 public void onRequestContinued() {
4588 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004589 }
4590
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004591 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004592 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004593 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004594 IAccountManagerResponse response = getResponseAndClose();
4595 if (response != null) {
4596 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004597 Log.v(TAG, getClass().getSimpleName()
4598 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004599 }
4600 try {
4601 response.onError(errorCode, errorMessage);
4602 } catch (RemoteException e) {
4603 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4604 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4605 }
4606 }
4607 } else {
4608 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4609 Log.v(TAG, "Session.onError: already closed");
4610 }
Fred Quintana60307342009-03-24 22:48:12 -07004611 }
4612 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004613
4614 /**
4615 * find the component name for the authenticator and initiate a bind
4616 * if no authenticator or the bind fails then return false, otherwise return true
4617 */
4618 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004619 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4620 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4621 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004622 if (authenticatorInfo == null) {
4623 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4624 Log.v(TAG, "there is no authenticator for " + authenticatorType
4625 + ", bailing out");
4626 }
4627 return false;
4628 }
4629
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004630 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004631 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004632 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4633 + " which isn't encryption aware");
4634 return false;
4635 }
4636
Fred Quintanab839afc2009-10-14 15:57:28 -07004637 Intent intent = new Intent();
4638 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4639 intent.setComponent(authenticatorInfo.componentName);
4640 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4641 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4642 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004643 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004644 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004645 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4646 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4647 }
4648 return false;
4649 }
4650
Fred Quintanab839afc2009-10-14 15:57:28 -07004651 return true;
4652 }
Fred Quintana60307342009-03-24 22:48:12 -07004653 }
4654
Svet Ganov5d09c992016-09-07 09:57:41 -07004655 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004656 MessageHandler(Looper looper) {
4657 super(looper);
4658 }
Costin Manolache3348f142009-09-29 18:58:36 -07004659
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004660 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004661 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004662 switch (msg.what) {
4663 case MESSAGE_TIMED_OUT:
4664 Session session = (Session)msg.obj;
4665 session.onTimedOut();
4666 break;
4667
Amith Yamasani5be347b2013-03-31 17:44:31 -07004668 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004669 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004670 break;
4671
Fred Quintana60307342009-03-24 22:48:12 -07004672 default:
4673 throw new IllegalStateException("unhandled message: " + msg.what);
4674 }
4675 }
4676 }
4677
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004678 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004679 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004680 }
4681
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004682 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004683 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004684 }
4685
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004686 /*
4687 * This function receives an opened writable database.
4688 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004689 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004690 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004691 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004692 }
4693
4694 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004695 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004696 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004697 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004698 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004699
4700 class LogRecordTask implements Runnable {
4701 private final String action;
4702 private final String tableName;
4703 private final long accountId;
4704 private final UserAccounts userAccount;
4705 private final int callingUid;
4706 private final long userDebugDbInsertionPoint;
4707
4708 LogRecordTask(final String action,
4709 final String tableName,
4710 final long accountId,
4711 final UserAccounts userAccount,
4712 final int callingUid,
4713 final long userDebugDbInsertionPoint) {
4714 this.action = action;
4715 this.tableName = tableName;
4716 this.accountId = accountId;
4717 this.userAccount = userAccount;
4718 this.callingUid = callingUid;
4719 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4720 }
4721
4722 public void run() {
4723 SQLiteStatement logStatement = userAccount.statementForLogging;
4724 logStatement.bindLong(1, accountId);
4725 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004726 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004727 logStatement.bindLong(4, callingUid);
4728 logStatement.bindString(5, tableName);
4729 logStatement.bindLong(6, userDebugDbInsertionPoint);
4730 logStatement.execute();
4731 logStatement.clearBindings();
4732 }
4733 }
4734
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004735 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4736 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004737 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004738 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004739 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004740 }
4741
4742 /*
4743 * This should only be called once to compile the sql statement for logging
4744 * and to find the insertion point.
4745 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004746 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4747 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4748 .calculateDebugTableInsertionPoint();
4749 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004750 }
4751
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004752 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004753 return asBinder();
4754 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004755
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004756 /**
4757 * Searches array of arguments for the specified string
4758 * @param args array of argument strings
4759 * @param value value to search for
4760 * @return true if the value is contained in the array
4761 */
4762 private static boolean scanArgs(String[] args, String value) {
4763 if (args != null) {
4764 for (String arg : args) {
4765 if (value.equals(arg)) {
4766 return true;
4767 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004768 }
4769 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004770 return false;
4771 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004772
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004773 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004774 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Kenny Root3abd75b2011-09-29 11:00:41 -07004775 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4776 != PackageManager.PERMISSION_GRANTED) {
4777 fout.println("Permission Denial: can't dump AccountsManager from from pid="
4778 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
4779 + " without permission " + android.Manifest.permission.DUMP);
4780 return;
4781 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004782 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004783 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004784
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004785 final List<UserInfo> users = getUserManager().getUsers();
4786 for (UserInfo user : users) {
4787 ipw.println("User " + user + ":");
4788 ipw.increaseIndent();
4789 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4790 ipw.println();
4791 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004792 }
4793 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004794
Amith Yamasani04e0d262012-02-14 11:50:53 -08004795 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4796 String[] args, boolean isCheckinRequest) {
4797 synchronized (userAccounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004798 if (isCheckinRequest) {
4799 // This is a checkin request. *Only* upload the account types and the count of each.
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004800 userAccounts.accountsDb.dumpDeAccountsTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004801 } else {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004802 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004803 Process.SYSTEM_UID, null /* packageName */, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004804 fout.println("Accounts: " + accounts.length);
4805 for (Account account : accounts) {
4806 fout.println(" " + account);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004807 }
Fred Quintana307da1a2010-01-21 14:24:20 -08004808
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004809 // Add debug information.
4810 fout.println();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004811 userAccounts.accountsDb.dumpDebugTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004812 fout.println();
4813 synchronized (mSessions) {
4814 final long now = SystemClock.elapsedRealtime();
4815 fout.println("Active Sessions: " + mSessions.size());
4816 for (Session session : mSessions.values()) {
4817 fout.println(" " + session.toDebugString(now));
4818 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004819 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004820
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004821 fout.println();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004822 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004823 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004824 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004825 }
4826
Amith Yamasani04e0d262012-02-14 11:50:53 -08004827 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004828 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004829 long identityToken = clearCallingIdentity();
4830 try {
4831 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4832 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4833 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004834
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004835 if (intent.getComponent() != null &&
4836 GrantCredentialsPermissionActivity.class.getName().equals(
4837 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004838 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004839 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004840 Context contextForUser = getContextForUser(new UserHandle(userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004841 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07004842 intent.addCategory(String.valueOf(notificationId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004843
Fred Quintana33f889a2009-09-14 17:31:26 -07004844 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004845 contextForUser.getText(R.string.notification_title).toString();
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004846 Notification n = new Notification.Builder(contextForUser)
4847 .setWhen(0)
4848 .setSmallIcon(android.R.drawable.stat_sys_warning)
4849 .setColor(contextForUser.getColor(
4850 com.android.internal.R.color.system_notification_accent_color))
4851 .setContentTitle(String.format(notificationTitleFormat, account.name))
4852 .setContentText(message)
4853 .setContentIntent(PendingIntent.getActivityAsUser(
4854 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004855 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004856 .build();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004857 installNotification(notificationId, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004858 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004859 } finally {
4860 restoreCallingIdentity(identityToken);
4861 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004862 }
4863
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004864 private void installNotification(int notificationId, final Notification notification,
4865 String packageName, int userId) {
4866 final long token = clearCallingIdentity();
4867 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004868 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004869 try {
4870 notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
4871 notificationId, notification, new int[1], userId);
4872 } catch (RemoteException e) {
4873 /* ignore - local call */
4874 }
4875 } finally {
4876 Binder.restoreCallingIdentity(token);
4877 }
Fred Quintana56285a62010-12-02 14:20:51 -08004878 }
4879
Fyodor Kupolovda993802016-09-21 14:47:10 -07004880 private void cancelNotification(int id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004881 cancelNotification(id, mContext.getPackageName(), user);
4882 }
4883
Fyodor Kupolovda993802016-09-21 14:47:10 -07004884 private void cancelNotification(int id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004885 long identityToken = clearCallingIdentity();
4886 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004887 INotificationManager service = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004888 service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
4889 } catch (RemoteException e) {
4890 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004891 } finally {
4892 restoreCallingIdentity(identityToken);
4893 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004894 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004895
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004896 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
4897 final long identity = Binder.clearCallingIdentity();
4898 try {
4899 IPackageManager pm = ActivityThread.getPackageManager();
4900 for (String perm : permissions) {
4901 if (pm.checkPermission(perm, packageName, userId)
4902 == PackageManager.PERMISSION_GRANTED) {
4903 return true;
4904 }
4905 }
4906 } catch (RemoteException e) {
4907 /* ignore - local call */
4908 } finally {
4909 Binder.restoreCallingIdentity(identity);
4910 }
4911 return false;
4912 }
4913
Ian Pedowitz358e51f2016-03-15 17:08:27 +00004914 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
4915 for (String perm : permissions) {
4916 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
4917 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4918 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
4919 }
4920 final int opCode = AppOpsManager.permissionToOpCode(perm);
4921 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
4922 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
4923 return true;
4924 }
4925 }
4926 }
4927 return false;
4928 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004929
Amith Yamasani67df64b2012-12-14 12:09:36 -08004930 private int handleIncomingUser(int userId) {
4931 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004932 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08004933 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
4934 } catch (RemoteException re) {
4935 // Shouldn't happen, local.
4936 }
4937 return userId;
4938 }
4939
Christopher Tateccbf84f2013-05-08 15:25:41 -07004940 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004941 String[] packages;
4942 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004943 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004944 packages = mPackageManager.getPackagesForUid(callingUid);
4945 } finally {
4946 Binder.restoreCallingIdentity(identityToken);
4947 }
4948 if (packages == null) {
4949 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004950 return false;
4951 }
Fred Quintana7be59642009-08-24 18:29:25 -07004952 for (String name : packages) {
4953 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004954 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08004955 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08004956 && (packageInfo.applicationInfo.privateFlags
4957 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07004958 return true;
4959 }
4960 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004961 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07004962 return false;
4963 }
4964 }
4965 return false;
4966 }
4967
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004968 private boolean permissionIsGranted(
4969 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004970 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
4971 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4972 Log.v(TAG, "Access to " + account + " granted calling uid is system");
4973 }
4974 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004975 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004976
4977 if (isPrivileged(callerUid)) {
4978 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4979 Log.v(TAG, "Access to " + account + " granted calling uid "
4980 + callerUid + " privileged");
4981 }
4982 return true;
4983 }
4984 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
4985 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4986 Log.v(TAG, "Access to " + account + " granted calling uid "
4987 + callerUid + " manages the account");
4988 }
4989 return true;
4990 }
4991 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
4992 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4993 Log.v(TAG, "Access to " + account + " granted calling uid "
4994 + callerUid + " user granted access");
4995 }
4996 return true;
4997 }
4998
4999 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5000 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5001 }
5002
5003 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005004 }
5005
Svetoslavf3f02ac2015-09-08 14:36:35 -07005006 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5007 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005008 if (accountType == null) {
5009 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005010 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005011 return getTypesVisibleToCaller(callingUid, userId,
5012 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005013 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005014 }
5015
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005016 // Method checks visibility for applications targeing API level below {@link
5017 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005018 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005019 private boolean checkGetAccountsPermission(String packageName, int userId) {
5020 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5021 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5022 }
5023
5024 private boolean checkReadContactsPermission(String packageName, int userId) {
5025 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5026 }
5027
5028 /**
5029 * Method checks package uid and signature with Authenticator which manages accountType.
5030 *
5031 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5032 * SIGNATURE_CHECK_MISMATCH otherwise.
5033 */
5034 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5035 if (accountType == null) {
5036 return SIGNATURE_CHECK_MISMATCH;
5037 }
5038
5039 long identityToken = Binder.clearCallingIdentity();
5040 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5041 try {
5042 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5043 } finally {
5044 Binder.restoreCallingIdentity(identityToken);
5045 }
5046 // Check for signature match with Authenticator.
5047 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5048 : serviceInfos) {
5049 if (accountType.equals(serviceInfo.type.type)) {
5050 if (serviceInfo.uid == callingUid) {
5051 return SIGNATURE_CHECK_UID_MATCH;
5052 }
5053 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5054 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5055 return SIGNATURE_CHECK_MATCH;
5056 }
5057 }
5058 }
5059 return SIGNATURE_CHECK_MISMATCH;
5060 }
5061
5062 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005063 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5064 if (accountType == null) {
5065 return false;
5066 } else {
5067 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5068 }
5069 }
5070
Svetoslavf3f02ac2015-09-08 14:36:35 -07005071 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5072 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005073 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005074 }
5075
5076 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005077 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005078 }
5079
5080 private List<String> getTypesForCaller(
5081 int callingUid, int userId, boolean isOtherwisePermitted) {
5082 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005083 long identityToken = Binder.clearCallingIdentity();
5084 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5085 try {
5086 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5087 } finally {
5088 Binder.restoreCallingIdentity(identityToken);
5089 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005090 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005091 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005092 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5093 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005094 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005095 }
5096 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005097 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005098 }
5099
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005100 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5101 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5102 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5103 if (account.name.equals(accountName)) {
5104 return true;
5105 }
5106 }
5107 }
5108 return false;
5109 }
5110
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005111 private static void checkManageUsersPermission(String message) {
5112 if (ActivityManager.checkComponentPermission(
5113 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5114 != PackageManager.PERMISSION_GRANTED) {
5115 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5116 }
5117 }
5118
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005119 private static void checkManageOrCreateUsersPermission(String message) {
5120 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5121 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5122 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5123 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5124 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5125 + message);
5126 }
5127 }
5128
Amith Yamasani04e0d262012-02-14 11:50:53 -08005129 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5130 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005131 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005132 return true;
5133 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005134 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005135 synchronized (accounts.cacheLock) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005136 long grantsCount;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005137 if (authTokenType != null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005138 grantsCount = accounts.accountsDb.findMatchingGrantsCount(callerUid, authTokenType,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005139 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005140 } else {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005141 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005142 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005143 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005144 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005145
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005146 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5147 // TODO: Skip this check when running automated tests. Replace this
5148 // with a more general solution.
5149 Log.d(TAG, "no credentials permission for usage of " + account + ", "
Amith Yamasani04e0d262012-02-14 11:50:53 -08005150 + authTokenType + " by uid " + callerUid
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005151 + " but ignoring since device is in test harness.");
5152 return true;
5153 }
5154 return permissionGranted;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005155 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005156 }
5157
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005158 private boolean isSystemUid(int callingUid) {
5159 String[] packages = null;
5160 long ident = Binder.clearCallingIdentity();
5161 try {
5162 packages = mPackageManager.getPackagesForUid(callingUid);
5163 } finally {
5164 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005165 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005166 if (packages != null) {
5167 for (String name : packages) {
5168 try {
5169 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5170 if (packageInfo != null
5171 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5172 != 0) {
5173 return true;
5174 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005175 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005176 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5177 }
5178 }
5179 } else {
5180 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005181 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005182 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005183 }
5184
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005185 /** Succeeds if any of the specified permissions are granted. */
5186 private void checkReadAccountsPermitted(
5187 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005188 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005189 int userId,
5190 String opPackageName) {
5191 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005192 String msg = String.format(
5193 "caller uid %s cannot access %s accounts",
5194 callingUid,
5195 accountType);
5196 Log.w(TAG, " " + msg);
5197 throw new SecurityException(msg);
5198 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005199 }
5200
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005201 private boolean canUserModifyAccounts(int userId, int callingUid) {
5202 // the managing app can always modify accounts
5203 if (isProfileOwner(callingUid)) {
5204 return true;
5205 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005206 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5207 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5208 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005209 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005210 return true;
5211 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005212
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005213 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5214 // the managing app can always modify accounts
5215 if (isProfileOwner(callingUid)) {
5216 return true;
5217 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005218 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5219 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005220 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005221 if (typesArray == null) {
5222 return true;
5223 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005224 for (String forbiddenType : typesArray) {
5225 if (forbiddenType.equals(accountType)) {
5226 return false;
5227 }
5228 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005229 return true;
5230 }
5231
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005232 private boolean isProfileOwner(int uid) {
5233 final DevicePolicyManagerInternal dpmi =
5234 LocalServices.getService(DevicePolicyManagerInternal.class);
5235 return (dpmi != null)
5236 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5237 }
5238
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005239 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005240 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5241 throws RemoteException {
5242 final int callingUid = getCallingUid();
5243
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005244 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005245 throw new SecurityException();
5246 }
5247
5248 if (value) {
5249 grantAppPermission(account, authTokenType, uid);
5250 } else {
5251 revokeAppPermission(account, authTokenType, uid);
5252 }
5253 }
5254
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005255 /**
5256 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5257 * <p>
5258 * Although this is public it can only be accessed via the AccountManagerService object
5259 * which is in the system. This means we don't need to protect it with permissions.
5260 * @hide
5261 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005262 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005263 if (account == null || authTokenType == null) {
5264 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005265 return;
5266 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005267 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005268 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005269 long accountId = accounts.accountsDb.findDeAccountId(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005270 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005271 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005272 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005273 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005274 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005275
5276 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005277 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005278
5279 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5280 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5281 : mAppPermissionChangeListeners) {
5282 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5283 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005284 }
5285
5286 /**
5287 * Don't allow callers with the given uid permission to get credentials for
5288 * account/authTokenType.
5289 * <p>
5290 * Although this is public it can only be accessed via the AccountManagerService object
5291 * which is in the system. This means we don't need to protect it with permissions.
5292 * @hide
5293 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005294 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005295 if (account == null || authTokenType == null) {
5296 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005297 return;
5298 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005299 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005300 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005301 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005302 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005303 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005304 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005305 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5306 accountId, authTokenType, uid);
5307 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005308 }
5309 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005310 accounts.accountsDb.endTransaction();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005311 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005312
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005313 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
5314 new UserHandle(accounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005315 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005316
5317 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5318 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5319 : mAppPermissionChangeListeners) {
5320 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5321 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005322 }
Fred Quintana56285a62010-12-02 14:20:51 -08005323
Amith Yamasani04e0d262012-02-14 11:50:53 -08005324 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5325 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005326 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005327 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005328 for (Account curAccount : oldAccountsForType) {
5329 if (!curAccount.equals(account)) {
5330 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005331 }
5332 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005333 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005334 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005335 } else {
5336 Account[] newAccountsForType = new Account[newAccountsList.size()];
5337 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005338 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005339 }
Fred Quintana56285a62010-12-02 14:20:51 -08005340 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005341 accounts.userDataCache.remove(account);
5342 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005343 accounts.previousNameCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005344 }
5345
5346 /**
5347 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005348 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5349 * processes and if you will return this account to apps you should return the result.
5350 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005351 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005352 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005353 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005354 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5355 Account[] newAccountsForType = new Account[oldLength + 1];
5356 if (accountsForType != null) {
5357 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005358 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005359 String token = account.getAccessId() != null ? account.getAccessId()
5360 : UUID.randomUUID().toString();
5361 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005362 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005363 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005364 }
5365
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005366 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
5367 String callingPackage, boolean includeManagedNotVisible) {
5368 // filter based on visibility.
5369 Map<Account, Integer> firstPass = new HashMap<>();
5370 for (Account account : unfiltered) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005371 int visibility = resolveAccountVisibility(account, callingPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005372 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5373 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5374 || (includeManagedNotVisible
5375 && (visibility
5376 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5377 firstPass.put(account, visibility);
5378 }
5379 }
5380 Map<Account, Integer> secondPass =
5381 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5382
5383 Account[] filtered = new Account[secondPass.size()];
5384 filtered = secondPass.keySet().toArray(filtered);
5385 return filtered;
5386 }
5387
5388 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
5389 Map<Account, Integer> unfiltered, int callingUid, String callingPackage) {
5390 // first part is to filter shared accounts.
5391 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005392 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005393 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005394 return unfiltered;
5395 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005396 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005397 if (user != null && user.isRestricted()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005398 String[] packages =
5399 mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005400 if (packages == null) {
5401 packages = new String[] {};
5402 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005403 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005404 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005405 // This might be a temporary way to specify a visible list
5406 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005407 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5408 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005409 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005410 return unfiltered;
5411 }
5412 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005413 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005414 if (ArrayUtils.isEmpty(sharedAccounts)) {
5415 return unfiltered;
5416 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005417 String requiredAccountType = "";
5418 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005419 // If there's an explicit callingPackage specified, check if that package
5420 // opted in to see restricted accounts.
5421 if (callingPackage != null) {
5422 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005423 if (pi != null && pi.restrictedAccountType != null) {
5424 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005425 }
5426 } else {
5427 // Otherwise check if the callingUid has a package that has opted in
5428 for (String packageName : packages) {
5429 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5430 if (pi != null && pi.restrictedAccountType != null) {
5431 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005432 break;
5433 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005434 }
5435 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005436 } catch (NameNotFoundException e) {
5437 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005438 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005439 Map<Account, Integer> filtered = new HashMap<>();
5440 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5441 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005442 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005443 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005444 } else {
5445 boolean found = false;
5446 for (Account shared : sharedAccounts) {
5447 if (shared.equals(account)) {
5448 found = true;
5449 break;
5450 }
5451 }
5452 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005453 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005454 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005455 }
5456 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005457 return filtered;
5458 } else {
5459 return unfiltered;
5460 }
5461 }
5462
Amith Yamasani27db4682013-03-30 17:07:47 -07005463 /*
5464 * packageName can be null. If not null, it should be used to filter out restricted accounts
5465 * that the package is not allowed to access.
5466 */
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005467 protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005468 int callingUid, String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005469 if (callingPackage == null) {
5470 callingPackage = getPackageNameForUid(callingUid);
5471 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005472 if (accountType != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005473 final Account[] accounts = userAccounts.accountCache.get(accountType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005474 if (accounts == null) {
5475 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005476 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005477 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5478 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005479 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005480 } else {
5481 int totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005482 for (Account[] accounts : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005483 totalLength += accounts.length;
5484 }
5485 if (totalLength == 0) {
5486 return EMPTY_ACCOUNT_ARRAY;
5487 }
5488 Account[] accounts = new Account[totalLength];
5489 totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005490 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005491 System.arraycopy(accountsOfType, 0, accounts, totalLength,
5492 accountsOfType.length);
5493 totalLength += accountsOfType.length;
5494 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005495 return filterAccounts(userAccounts, accounts, callingUid, callingPackage,
5496 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005497 }
5498 }
5499
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005500 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005501 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005502 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005503 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005504 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005505 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005506 }
5507 if (value == null) {
5508 userDataForAccount.remove(key);
5509 } else {
5510 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005511 }
5512 }
5513
Carlos Valdivia91979be2015-05-22 14:11:35 -07005514 protected String readCachedTokenInternal(
5515 UserAccounts accounts,
5516 Account account,
5517 String tokenType,
5518 String callingPackage,
5519 byte[] pkgSigDigest) {
5520 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005521 return accounts.accountTokenCaches.get(
5522 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07005523 }
5524 }
5525
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005526 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005527 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005528 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005529 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005530 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005531 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005532 }
5533 if (value == null) {
5534 authTokensForAccount.remove(key);
5535 } else {
5536 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005537 }
5538 }
5539
Amith Yamasani04e0d262012-02-14 11:50:53 -08005540 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5541 String authTokenType) {
5542 synchronized (accounts.cacheLock) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005543 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005544 if (authTokensForAccount == null) {
5545 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005546 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005547 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005548 }
5549 return authTokensForAccount.get(authTokenType);
5550 }
5551 }
5552
Simranjit Kohli858511c2016-03-10 18:36:11 +00005553 protected String readUserDataInternalLocked(
5554 UserAccounts accounts, Account account, String key) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005555 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005556 if (userDataForAccount == null) {
5557 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005558 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005559 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005560 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005561 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005562 }
5563
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005564 private Context getContextForUser(UserHandle user) {
5565 try {
5566 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5567 } catch (NameNotFoundException e) {
5568 // Default to mContext, not finding the package system is running as is unlikely.
5569 return mContext;
5570 }
5571 }
Sandra Kwan78812282015-11-04 11:19:47 -08005572
5573 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5574 try {
5575 response.onResult(result);
5576 } catch (RemoteException e) {
5577 // if the caller is dead then there is no one to care about remote
5578 // exceptions
5579 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5580 Log.v(TAG, "failure while notifying response", e);
5581 }
5582 }
5583 }
5584
5585 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5586 String errorMessage) {
5587 try {
5588 response.onError(errorCode, errorMessage);
5589 } catch (RemoteException e) {
5590 // if the caller is dead then there is no one to care about remote
5591 // exceptions
5592 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5593 Log.v(TAG, "failure while notifying response", e);
5594 }
5595 }
5596 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005597
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005598 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005599 private final Object mLock = new Object();
5600
5601 @GuardedBy("mLock")
5602 private AccountManagerBackupHelper mBackupHelper;
5603
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005604 @Override
5605 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5606 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5607 if (account == null) {
5608 Slog.w(TAG, "account cannot be null");
5609 return;
5610 }
5611 if (packageName == null) {
5612 Slog.w(TAG, "packageName cannot be null");
5613 return;
5614 }
5615 if (userId < UserHandle.USER_SYSTEM) {
5616 Slog.w(TAG, "user id must be concrete");
5617 return;
5618 }
5619 if (callback == null) {
5620 Slog.w(TAG, "callback cannot be null");
5621 return;
5622 }
5623
Svet Ganovf6d424f12016-09-20 20:18:53 -07005624 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5625 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005626 Bundle result = new Bundle();
5627 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5628 callback.sendResult(result);
5629 return;
5630 }
5631
5632 final int uid;
5633 try {
5634 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5635 } catch (NameNotFoundException e) {
5636 Slog.e(TAG, "Unknown package " + packageName);
5637 return;
5638 }
5639
5640 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005641 final UserAccounts userAccounts;
5642 synchronized (mUsers) {
5643 userAccounts = mUsers.get(userId);
5644 }
5645 doNotification(userAccounts, account, null, intent, packageName, userId);
5646 }
5647
5648 @Override
5649 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5650 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5651 mAppPermissionChangeListeners.add(listener);
5652 }
5653
5654 @Override
5655 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5656 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005657 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005658
5659 @Override
5660 public byte[] backupAccountAccessPermissions(int userId) {
5661 synchronized (mLock) {
5662 if (mBackupHelper == null) {
5663 mBackupHelper = new AccountManagerBackupHelper(
5664 AccountManagerService.this, this);
5665 }
5666 return mBackupHelper.backupAccountAccessPermissions(userId);
5667 }
5668 }
5669
5670 @Override
5671 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5672 synchronized (mLock) {
5673 if (mBackupHelper == null) {
5674 mBackupHelper = new AccountManagerBackupHelper(
5675 AccountManagerService.this, this);
5676 }
5677 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5678 }
5679 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005680 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005681
5682 @VisibleForTesting
5683 static class Injector {
5684 private final Context mContext;
5685
5686 public Injector(Context context) {
5687 mContext = context;
5688 }
5689
5690 Looper getMessageHandlerLooper() {
5691 ServiceThread serviceThread = new ServiceThread(TAG,
5692 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5693 serviceThread.start();
5694 return serviceThread.getLooper();
5695 }
5696
5697 Context getContext() {
5698 return mContext;
5699 }
5700
5701 void addLocalService(AccountManagerInternal service) {
5702 LocalServices.addService(AccountManagerInternal.class, service);
5703 }
5704
5705 String getDeDatabaseName(int userId) {
5706 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5707 AccountsDb.DE_DATABASE_NAME);
5708 return databaseFile.getPath();
5709 }
5710
5711 String getCeDatabaseName(int userId) {
5712 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5713 AccountsDb.CE_DATABASE_NAME);
5714 return databaseFile.getPath();
5715 }
5716
5717 String getPreNDatabaseName(int userId) {
5718 File systemDir = Environment.getDataSystemDirectory();
5719 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5720 PRE_N_DATABASE_NAME);
5721 if (userId == 0) {
5722 // Migrate old file, if it exists, to the new location.
5723 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005724 // accidentally created in the old location,
5725 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005726 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5727 if (oldFile.exists() && !databaseFile.exists()) {
5728 // Check for use directory; create if it doesn't exist, else renameTo will fail
5729 File userDir = Environment.getUserSystemDirectory(userId);
5730 if (!userDir.exists()) {
5731 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005732 throw new IllegalStateException(
5733 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005734 }
5735 }
5736 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005737 throw new IllegalStateException(
5738 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005739 }
5740 }
5741 }
5742 return databaseFile.getPath();
5743 }
5744
5745 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5746 return new AccountAuthenticatorCache(mContext);
5747 }
5748
5749 INotificationManager getNotificationManager() {
5750 return NotificationManager.getService();
5751 }
5752 }
Fred Quintana60307342009-03-24 22:48:12 -07005753}