blob: fdd7cb13920451cbb457fb91864c1f15d2f92829 [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
484 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
485 getUserAccounts(UserHandle.getUserId(callingUid)));
486 }
487
488 /*
489 * accountTypes may not be null
490 */
491 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
492 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
493 int uid = 0;
494 try {
495 uid = mPackageManager.getPackageUidAsUser(packageName,
496 UserHandle.getUserId(callingUid));
497 } catch (NameNotFoundException e) {
498 Log.d(TAG, "Package not found " + e.getMessage());
499 return new HashMap<>();
500 }
501
502 Map<Account, Integer> result = new HashMap<>();
503 for (String accountType : accountTypes) {
504 synchronized (accounts.cacheLock) {
505 final Account[] accountsOfType = accounts.accountCache.get(accountType);
506 if (accountsOfType != null) {
507 for (Account account : accountsOfType) {
508 result.put(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800509 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800510 }
511 }
512 }
513 }
514 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800515 }
516
517 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800518 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800519 if (account == null) throw new IllegalArgumentException("account is null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700520 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800521 int userId = UserHandle.getUserId(callingUid);
522 UserAccounts accounts = getUserAccounts(userId);
523 if (!isAccountManagedByCaller(account.type, callingUid, userId)
524 && !isSystemUid(callingUid)) {
525 String msg =
526 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700527 throw new SecurityException(msg);
528 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800529 return getPackagesAndVisibilityForAccount(account, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800530 }
531
532 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800533 * Returns all package names and visibility values, which were set for given account.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800534 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800535 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800536 * @param accounts UserAccount that currently hosts the account and application
537 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800538 * @return Map from package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800539 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800540 private Map<String, Integer> getPackagesAndVisibilityForAccount(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800541 UserAccounts accounts) {
542 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
543 try {
544 return accounts.accountsDb.findAllVisibilityValuesForAccount(account);
545 } finally {
546 StrictMode.setThreadPolicy(oldPolicy);
547 }
548
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700549 }
550
551 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800552 public int getAccountVisibility(Account a, String packageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800553 if (a == null) throw new IllegalArgumentException("account is null");
554 int callingUid = Binder.getCallingUid();
555 if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
556 && !isSystemUid(callingUid)) {
557 String msg = String.format(
558 "uid %s cannot get secrets for accounts of type: %s",
559 callingUid,
560 a.type);
561 throw new SecurityException(msg);
562 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800563 return getAccountVisibility(a, packageName,
564 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800565 }
566
567 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800568 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800569 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800570 * @param account The account to check visibility.
571 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800572 * @param accounts UserAccount that currently hosts the account and application
573 *
574 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
575 *
576 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800577 private int getAccountVisibility(Account account, String packageName, UserAccounts accounts) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800578 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
579 try {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800580 Integer visibility = accounts.accountsDb.findAccountVisibility(account, packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800581 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
582 } finally {
583 StrictMode.setThreadPolicy(oldPolicy);
584 }
585 }
586
587 /**
588 * Method which handles default values for Account visibility.
589 *
590 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800591 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800592 * @param accounts UserAccount that currently hosts the account and application
593 *
594 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
595 *
596 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800597 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800598 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800599 Preconditions.checkNotNull(packageName, "packageName cannot be null");
600
601 int uid = -1;
602 try {
603 long identityToken = clearCallingIdentity();
604 try {
605 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
606 } finally {
607 restoreCallingIdentity(identityToken);
608 }
609 } catch (NameNotFoundException e) {
610 Log.d(TAG, "Package not found " + e.getMessage());
611 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800612 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800613
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800614 // System visibility can not be restricted.
615 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
616 return AccountManager.VISIBILITY_VISIBLE;
617 }
618
619 int signatureCheckResult =
620 checkPackageSignature(account.type, uid, accounts.userId);
621
622 // Authenticator can not restrict visibility to itself.
623 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
624 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
625 }
626
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800627 if (isSpecialPackageKey(packageName)) {
628 Log.d(TAG, "Package name is forbidden: " + packageName);
629 return AccountManager.VISIBILITY_NOT_VISIBLE;
630 }
631
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800632 // Return stored value if it was set.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800633 int visibility = getAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800634
635 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
636 return visibility;
637 }
638
639 if (isPermittedForPackage(packageName, accounts.userId,
640 Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
641 return AccountManager.VISIBILITY_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800642 }
643 // Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800644 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800645 return AccountManager.VISIBILITY_VISIBLE;
646 }
647 // Apps with READ_CONTACTS permission get visibility by default even post O.
648 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
649
650 boolean preO = isPreOApplication(packageName);
651 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
652 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
653 || canReadContacts) {
654 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
655 // match.
656 visibility = getAccountVisibility(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800657 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800658 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
659 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
660 }
661 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800662 visibility = getAccountVisibility(account,
663 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800664 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
665 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
666 }
667 }
668 return visibility;
669 }
670
671 /**
672 * Checks targetSdk for a package;
673 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800674 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800675 *
676 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
677 * undefined
678 */
679 private boolean isPreOApplication(String packageName) {
680 try {
681 long identityToken = clearCallingIdentity();
682 ApplicationInfo applicationInfo;
683 try {
684 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
685 } finally {
686 restoreCallingIdentity(identityToken);
687 }
688
689 if (applicationInfo != null) {
690 int version = applicationInfo.targetSdkVersion;
691 return version < android.os.Build.VERSION_CODES.O;
692 }
693 return true;
694 } catch (NameNotFoundException e) {
695 Log.d(TAG, "Package not found " + e.getMessage());
696 return true;
697 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800698 }
699
700 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800701 public boolean setAccountVisibility(Account a, String packageName, int newVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800702 if (a == null) throw new IllegalArgumentException("account is null");
703 int callingUid = Binder.getCallingUid();
704 if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
705 && !isSystemUid(callingUid)) {
706 String msg = String.format(
707 "uid %s cannot get secrets for accounts of type: %s",
708 callingUid,
709 a.type);
710 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700711 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800712 return setAccountVisibility(a, packageName, newVisibility, true /* notify */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800713 getUserAccounts(UserHandle.getUserId(callingUid)));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700714 }
715
716 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800717 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700718 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800719 * @param account Account to update visibility.
720 * @param packageName Package name for which visibility is updated.
721 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800722 * @param notify if the flag is set applications will get notification about visibility change
723 * @param accounts UserAccount that currently hosts the account and application
724 *
725 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700726 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800727 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800728 boolean notify, UserAccounts accounts) {
729 synchronized (accounts.cacheLock) {
730 LinkedHashSet<String> interestedPackages;
731 if (notify) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800732 if (isSpecialPackageKey(packageName)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800733 interestedPackages = getRequestingPackageNames(account.type, accounts);
734 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800735 if (!packageExistsForUser(packageName, accounts.userId)) {
736 return false; // package is not installed.
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100737 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800738 interestedPackages = new LinkedHashSet<>();
739 interestedPackages.add(packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800740 }
741 } else {
742 // Notifications will not be send.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800743 if (!isSpecialPackageKey(packageName) &&
744 !packageExistsForUser(packageName, accounts.userId)) {
745 // package is not installed and not meta value.
746 return false;
747 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800748 interestedPackages = new LinkedHashSet<>();
749 }
750 Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
751
752 final long accountId = accounts.accountsDb.findDeAccountId(account);
753 if (accountId < 0) {
754 return false;
755 }
756 int index = 0;
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800757 for (String interestedPackage : interestedPackages) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800758 interestedPackagesVisibility[index++] =
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800759 resolveAccountVisibility(account, interestedPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800760 }
761
762 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
763 try {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800764 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
765 newVisibility)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800766 return false;
767 }
768 } finally {
769 StrictMode.setThreadPolicy(oldPolicy);
770 }
771
772 index = 0;
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800773 for (String interestedPackage : interestedPackages) {
774 int visibility = resolveAccountVisibility(account, interestedPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800775 if (visibility != interestedPackagesVisibility[index++]) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800776 sendNotification(interestedPackage, account, accounts.userId);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700777 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700778 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800779 if (notify) {
780 sendAccountsChangedBroadcast(accounts.userId);
781 }
782 return true;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700783 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700784 }
785
786 /**
Dmitry Dementyev52745472016-12-02 10:27:45 -0800787 * Sends a direct intent to a package, notifying it of a visible account change.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700788 *
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800789 * @param packageName to send Account to
790 * @param account to send to package
791 * @param userId User
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700792 */
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800793 private void sendNotification(String packageName, Account account, int userId) {
794 // TODO send notification so apps subscribed in runtime.
795 }
796
797 private void sendNotification(Account account, UserAccounts accounts) {
798 LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
799 accounts);
800 for (String packageName : interestedPackages) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800801 int visibility = resolveAccountVisibility(account, packageName, accounts);
802 if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
803 sendNotification(packageName, account, accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800804 }
805 }
806 }
807
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800808 LinkedHashSet<String> getRequestingPackageNames(String accountType, UserAccounts accounts) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800809 // TODO return packages registered to get notifications.
810 return new LinkedHashSet<String>();
811 }
812
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800813 private boolean packageExistsForUser(String packageName, int userId) {
814 try {
815 long identityToken = clearCallingIdentity();
816 try {
817 mPackageManager.getPackageUidAsUser(packageName, userId);
818 return true; // package exist
819 } finally {
820 restoreCallingIdentity(identityToken);
821 }
822 } catch (NameNotFoundException e) {
823 return false;
824 }
825 }
826
827 /**
828 * Returns true if packageName is one of special values.
829 */
830 private boolean isSpecialPackageKey(String packageName) {
831 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
832 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
833 }
834
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800835 private void sendAccountsChangedBroadcast(int userId) {
836 Log.i(TAG, "the accounts changed, sending broadcast of "
837 + ACCOUNTS_CHANGED_INTENT.getAction());
838 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700839 }
840
841 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700842 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
843 throws RemoteException {
844 try {
845 return super.onTransact(code, data, reply, flags);
846 } catch (RuntimeException e) {
847 // The account manager only throws security exceptions, so let's
848 // log all others.
849 if (!(e instanceof SecurityException)) {
850 Slog.wtf(TAG, "Account Manager Crash", e);
851 }
852 throw e;
853 }
854 }
855
Amith Yamasani258848d2012-08-10 17:06:33 -0700856 private UserManager getUserManager() {
857 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700858 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700859 }
860 return mUserManager;
861 }
862
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700863 /**
864 * Validate internal set of accounts against installed authenticators for
865 * given user. Clears cached authenticators before validating.
866 */
867 public void validateAccounts(int userId) {
868 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700869 // Invalidate user-specific cache to make sure we catch any
870 // removed authenticators.
871 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
872 }
873
874 /**
875 * Validate internal set of accounts against installed authenticators for
876 * given user. Clear cached authenticators before validating when requested.
877 */
878 private void validateAccountsInternal(
879 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700880 if (Log.isLoggable(TAG, Log.DEBUG)) {
881 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700882 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600883 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700884 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700885
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700886 if (invalidateAuthenticatorCache) {
887 mAuthenticatorCache.invalidateCache(accounts.userId);
888 }
889
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700890 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
891 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700892 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700893
Amith Yamasani04e0d262012-02-14 11:50:53 -0800894 synchronized (accounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800895 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800896
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700897 // Get a map of stored authenticator types to UID
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700898 final AccountsDb accountsDb = accounts.accountsDb;
899 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800900 // Create a list of authenticator type whose previous uid no longer exists
901 HashSet<String> obsoleteAuthType = Sets.newHashSet();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700902 SparseBooleanArray knownUids = null;
903 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
904 String type = authToUidEntry.getKey();
905 int uid = authToUidEntry.getValue();
906 Integer knownUid = knownAuth.get(type);
907 if (knownUid != null && uid == knownUid) {
908 // Remove it from the knownAuth list if it's unchanged.
909 knownAuth.remove(type);
910 } else {
911 /*
912 * The authenticator is presently not cached and should only be triggered
913 * when we think an authenticator has been removed (or is being updated).
914 * But we still want to check if any data with the associated uid is
915 * around. This is an (imperfect) signal that the package may be updating.
916 *
917 * A side effect of this is that an authenticator sharing a uid with
918 * multiple apps won't get its credentials wiped as long as some app with
919 * that uid is still on the device. But I suspect that this is a rare case.
920 * And it isn't clear to me how an attacker could really exploit that
921 * feature.
922 *
923 * The upshot is that we don't have to worry about accounts getting
924 * uninstalled while the authenticator's package is being updated.
925 *
926 */
927 if (knownUids == null) {
928 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800929 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700930 if (!knownUids.get(uid)) {
931 // The authenticator is not presently available to the cache. And the
932 // package no longer has a data directory (so we surmise it isn't updating).
933 // So purge its data from the account databases.
934 obsoleteAuthType.add(type);
935 // And delete it from the TABLE_META
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700936 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800937 }
938 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800939 }
940
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700941 // Add the newly registered authenticator to TABLE_META. If old authenticators have
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700942 // been re-enabled (after being updated for example), then we just overwrite the old
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700943 // values.
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700944 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700945 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800946 }
947
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700948 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800949 try {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800950 accounts.accountCache.clear();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700951 final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700952 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
953 final long accountId = accountEntry.getKey();
954 final Account account = accountEntry.getValue();
955 if (obsoleteAuthType.contains(account.type)) {
956 Slog.w(TAG, "deleting account " + account.name + " because type "
957 + account.type + "'s registered authenticator no longer exist.");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700958 accountsDb.beginTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700959 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700960 accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700961 // Also delete from CE table if user is unlocked; if user is currently
962 // locked the account will be removed later by syncDeCeAccountsLocked
963 if (userUnlocked) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700964 accountsDb.deleteCeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700965 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700966 accountsDb.setTransactionSuccessful();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700967 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700968 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700969 }
Fred Quintana56285a62010-12-02 14:20:51 -0800970 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700971
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700972 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
973 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700974
Amith Yamasani04e0d262012-02-14 11:50:53 -0800975 accounts.userDataCache.remove(account);
976 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700977 accounts.accountTokenCaches.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800978 LinkedHashSet<String> interestedPackages =
979 getRequestingPackageNames(account.type, accounts);
980 for (String packageName : interestedPackages) {
981 sendNotification(packageName, null, accounts.userId);
982 }
983
Fred Quintana56285a62010-12-02 14:20:51 -0800984 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700985 ArrayList<String> accountNames = accountNamesByType.get(account.type);
Fred Quintana56285a62010-12-02 14:20:51 -0800986 if (accountNames == null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700987 accountNames = new ArrayList<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700988 accountNamesByType.put(account.type, accountNames);
Fred Quintana56285a62010-12-02 14:20:51 -0800989 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700990 accountNames.add(account.name);
Fred Quintana56285a62010-12-02 14:20:51 -0800991 }
992 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700993 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
Fred Quintana56285a62010-12-02 14:20:51 -0800994 final String accountType = cur.getKey();
995 final ArrayList<String> accountNames = cur.getValue();
996 final Account[] accountsForType = new Account[accountNames.size()];
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700997 for (int i = 0; i < accountsForType.length; i++) {
Svet Ganovf6d424f12016-09-20 20:18:53 -0700998 accountsForType[i] = new Account(accountNames.get(i), accountType,
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700999 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001000 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001001 accounts.accountCache.put(accountType, accountsForType);
Fred Quintanaafa92b82009-12-01 16:27:03 -08001002 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001003 } finally {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001004 if (accountDeleted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001005 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001006 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001007 }
1008 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001009 }
1010
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001011 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1012 // Get the UIDs of all apps that might have data on the device. We want
1013 // to preserve user data if the app might otherwise be storing data.
1014 List<PackageInfo> pkgsWithData =
1015 mPackageManager.getInstalledPackagesAsUser(
1016 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1017 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1018 for (PackageInfo pkgInfo : pkgsWithData) {
1019 if (pkgInfo.applicationInfo != null
1020 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1021 knownUids.put(pkgInfo.applicationInfo.uid, true);
1022 }
1023 }
1024 return knownUids;
1025 }
1026
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001027 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001028 Context context,
1029 int userId) {
1030 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001031 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1032 }
1033
1034 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1035 IAccountAuthenticatorCache authCache,
1036 int userId) {
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001037 HashMap<String, Integer> knownAuth = new HashMap<>();
1038 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1039 .getAllServices(userId)) {
1040 knownAuth.put(service.type.type, service.uid);
1041 }
1042 return knownAuth;
1043 }
1044
Amith Yamasani04e0d262012-02-14 11:50:53 -08001045 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001046 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001047 }
1048
1049 protected UserAccounts getUserAccounts(int userId) {
1050 synchronized (mUsers) {
1051 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001052 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001053 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001054 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1055 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001056 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001057 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001058 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001059 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001060 validateAccounts = true;
1061 }
1062 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001063 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001064 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
1065 synchronized (accounts.cacheLock) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001066 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001067 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001068 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001069 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001070 }
1071 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001072 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001073 }
1074 return accounts;
1075 }
1076 }
1077
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001078 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1079 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001080 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001081 if (!accountsToRemove.isEmpty()) {
1082 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1083 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001084 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1085 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001086
1087 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001088 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001089 }
1090 }
1091 }
1092
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001093 private void purgeOldGrantsAll() {
1094 synchronized (mUsers) {
1095 for (int i = 0; i < mUsers.size(); i++) {
1096 purgeOldGrants(mUsers.valueAt(i));
1097 }
1098 }
1099 }
1100
1101 private void purgeOldGrants(UserAccounts accounts) {
1102 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001103 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001104 for (int uid : uids) {
1105 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1106 if (packageExists) {
1107 continue;
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001108 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001109 Log.d(TAG, "deleting grants for UID " + uid
1110 + " because its package is no longer installed");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001111 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001112 }
1113 }
1114 }
1115
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001116 private void removeVisibilityValuesForPackage(String packageName) {
1117 synchronized (mUsers) {
1118 for (int i = 0; i < mUsers.size(); i++) {
1119 UserAccounts accounts = mUsers.valueAt(i);
1120 try {
1121 int uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1122 } catch (NameNotFoundException e) {
1123 // package does not exist - remove visibility values
1124 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
1125 }
1126 }
1127 }
1128 }
1129
Amith Yamasani13593602012-03-22 16:16:17 -07001130 private void onUserRemoved(Intent intent) {
Amith Yamasani2a003292012-08-14 18:25:45 -07001131 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Amith Yamasani13593602012-03-22 16:16:17 -07001132 if (userId < 1) return;
1133
1134 UserAccounts accounts;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001135 boolean userUnlocked;
Amith Yamasani13593602012-03-22 16:16:17 -07001136 synchronized (mUsers) {
1137 accounts = mUsers.get(userId);
1138 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001139 userUnlocked = mLocalUnlockedUsers.get(userId);
1140 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001141 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001142 if (accounts != null) {
1143 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001144 accounts.accountsDb.close();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001145 }
Amith Yamasani13593602012-03-22 16:16:17 -07001146 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001147 Log.i(TAG, "Removing database files for user " + userId);
Fyodor Kupolovda993802016-09-21 14:47:10 -07001148 File dbFile = new File(mInjector.getDeDatabaseName(userId));
Amith Yamasani13593602012-03-22 16:16:17 -07001149
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001150 AccountsDb.deleteDbFileWarnIfFailed(dbFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001151 // Remove CE file if user is unlocked, or FBE is not enabled
1152 boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
1153 if (!fbeEnabled || userUnlocked) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001154 File ceDb = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001155 if (ceDb.exists()) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001156 AccountsDb.deleteDbFileWarnIfFailed(ceDb);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001157 }
1158 }
1159 }
1160
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001161 @VisibleForTesting
1162 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001163 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1164 }
1165
1166 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001167 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1168 Log.v(TAG, "onUserUnlocked " + userId);
1169 }
1170 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001171 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001172 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001173 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001174 syncSharedAccounts(userId);
1175 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001176
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001177 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001178 // Check if there's a shared account that needs to be created as an account
1179 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1180 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001181 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001182 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001183 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001184 : UserHandle.USER_SYSTEM;
1185 if (parentUserId < 0) {
1186 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1187 return;
1188 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001189 for (Account sa : sharedAccounts) {
1190 if (ArrayUtils.contains(accounts, sa)) continue;
1191 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001192 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001193 }
1194 }
1195
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001196 @Override
1197 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001198 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001199 }
1200
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001201 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001202 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001203 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001204 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1205 Log.v(TAG, "getPassword: " + account
1206 + ", caller's uid " + Binder.getCallingUid()
1207 + ", pid " + Binder.getCallingPid());
1208 }
Fred Quintana382601f2010-03-25 12:25:10 -07001209 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001210 int userId = UserHandle.getCallingUserId();
1211 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001212 String msg = String.format(
1213 "uid %s cannot get secrets for accounts of type: %s",
1214 callingUid,
1215 account.type);
1216 throw new SecurityException(msg);
1217 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001218 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001219 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001220 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001221 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001222 } finally {
1223 restoreCallingIdentity(identityToken);
1224 }
1225 }
1226
Amith Yamasani04e0d262012-02-14 11:50:53 -08001227 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001228 if (account == null) {
1229 return null;
1230 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001231 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001232 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1233 return null;
1234 }
Fred Quintana31957f12009-10-21 13:43:10 -07001235
Amith Yamasani04e0d262012-02-14 11:50:53 -08001236 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001237 return accounts.accountsDb.findAccountPasswordByNameAndType(account.name, account.type);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001238 }
1239 }
1240
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001241 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001242 public String getPreviousName(Account account) {
1243 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1244 Log.v(TAG, "getPreviousName: " + account
1245 + ", caller's uid " + Binder.getCallingUid()
1246 + ", pid " + Binder.getCallingPid());
1247 }
1248 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001249 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001250 long identityToken = clearCallingIdentity();
1251 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001252 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001253 return readPreviousNameInternal(accounts, account);
1254 } finally {
1255 restoreCallingIdentity(identityToken);
1256 }
1257 }
1258
1259 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1260 if (account == null) {
1261 return null;
1262 }
1263 synchronized (accounts.cacheLock) {
1264 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1265 if (previousNameRef == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001266 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001267 previousNameRef = new AtomicReference<>(previousName);
1268 accounts.previousNameCache.put(account, previousNameRef);
1269 return previousName;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001270 } else {
1271 return previousNameRef.get();
1272 }
1273 }
1274 }
1275
1276 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001277 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001278 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001279 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001280 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1281 account, key, callingUid, Binder.getCallingPid());
1282 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001283 }
Fred Quintana382601f2010-03-25 12:25:10 -07001284 if (account == null) throw new IllegalArgumentException("account is null");
1285 if (key == null) throw new IllegalArgumentException("key is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001286 int userId = UserHandle.getCallingUserId();
1287 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001288 String msg = String.format(
1289 "uid %s cannot get user data for accounts of type: %s",
1290 callingUid,
1291 account.type);
1292 throw new SecurityException(msg);
1293 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001294 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001295 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1296 return null;
1297 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001298 long identityToken = clearCallingIdentity();
1299 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001300 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00001301 synchronized (accounts.cacheLock) {
1302 if (!accountExistsCacheLocked(accounts, account)) {
1303 return null;
1304 }
1305 return readUserDataInternalLocked(accounts, account, key);
1306 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001307 } finally {
1308 restoreCallingIdentity(identityToken);
1309 }
1310 }
1311
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001312 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001313 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001314 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001315 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1316 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001317 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001318 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001319 + ", pid " + Binder.getCallingPid());
1320 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001321 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001322 if (isCrossUser(callingUid, userId)) {
1323 throw new SecurityException(
1324 String.format(
1325 "User %s tying to get authenticator types for %s" ,
1326 UserHandle.getCallingUserId(),
1327 userId));
1328 }
1329
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001330 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001331 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001332 return getAuthenticatorTypesInternal(userId);
1333
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001334 } finally {
1335 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001336 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001337 }
1338
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001339 /**
1340 * Should only be called inside of a clearCallingIdentity block.
1341 */
1342 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001343 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001344 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1345 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1346 AuthenticatorDescription[] types =
1347 new AuthenticatorDescription[authenticatorCollection.size()];
1348 int i = 0;
1349 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1350 : authenticatorCollection) {
1351 types[i] = authenticator.type;
1352 i++;
1353 }
1354 return types;
1355 }
1356
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001357 private boolean isCrossUser(int callingUid, int userId) {
1358 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001359 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001360 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001361 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1362 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001363 }
1364
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001365 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001366 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001367 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001368 }
1369
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001370 @Override
1371 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001372 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001373 int callingUid = Binder.getCallingUid();
1374 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1375 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001376 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001377 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001378 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1379 final UserAccounts toAccounts = getUserAccounts(userTo);
1380 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001381 if (response != null) {
1382 Bundle result = new Bundle();
1383 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1384 try {
1385 response.onResult(result);
1386 } catch (RemoteException e) {
1387 Slog.w(TAG, "Failed to report error back to the client." + e);
1388 }
1389 }
1390 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001391 }
1392
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001393 Slog.d(TAG, "Copying account " + account.name
1394 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001395 long identityToken = clearCallingIdentity();
1396 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001397 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001398 false /* stripAuthTokenFromResult */, account.name,
1399 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001400 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001401 protected String toDebugString(long now) {
1402 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1403 + ", " + account.type;
1404 }
1405
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001406 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001407 public void run() throws RemoteException {
1408 mAuthenticator.getAccountCredentialsForCloning(this, account);
1409 }
1410
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001411 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001412 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001413 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001414 if (result != null
1415 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1416 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001417 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001418 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001419 super.onResult(result);
1420 }
1421 }
1422 }.bind();
1423 } finally {
1424 restoreCallingIdentity(identityToken);
1425 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001426 }
1427
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001428 @Override
1429 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001430 final int callingUid = Binder.getCallingUid();
1431 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1432 String msg = String.format(
1433 "accountAuthenticated( account: %s, callerUid: %s)",
1434 account,
1435 callingUid);
1436 Log.v(TAG, msg);
1437 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001438 if (account == null) {
1439 throw new IllegalArgumentException("account is null");
1440 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001441 int userId = UserHandle.getCallingUserId();
1442 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001443 String msg = String.format(
1444 "uid %s cannot notify authentication for accounts of type: %s",
1445 callingUid,
1446 account.type);
1447 throw new SecurityException(msg);
1448 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001449
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001450 if (!canUserModifyAccounts(userId, callingUid) ||
1451 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001452 return false;
1453 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001454
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001455 long identityToken = clearCallingIdentity();
1456 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001457 UserAccounts accounts = getUserAccounts(userId);
1458 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001459 } finally {
1460 restoreCallingIdentity(identityToken);
1461 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001462 }
1463
1464 private boolean updateLastAuthenticatedTime(Account account) {
1465 final UserAccounts accounts = getUserAccountsForCaller();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001466 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001467 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001468 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001469 }
1470
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001471 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001472 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1473 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001474 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001475 long id = clearCallingIdentity();
1476 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001477 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001478 false /* stripAuthTokenFromResult */, account.name,
1479 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001480 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001481 protected String toDebugString(long now) {
1482 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1483 + ", " + account.type;
1484 }
1485
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001486 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001487 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001488 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001489 UserAccounts owner = getUserAccounts(parentUserId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001490 synchronized (owner.cacheLock) {
Svetoslavf3f02ac2015-09-08 14:36:35 -07001491 for (Account acc : getAccounts(parentUserId,
1492 mContext.getOpPackageName())) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001493 if (acc.equals(account)) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001494 mAuthenticator.addAccountFromCredentials(
1495 this, account, accountCredentials);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001496 break;
1497 }
1498 }
1499 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001500 }
1501
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001502 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001503 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001504 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001505 // TODO: Anything to do if if succedded?
1506 // TODO: If it failed: Show error notification? Should we remove the shadow
1507 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001508 // TODO: what we do with the visibility?
1509
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001510 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001511 }
1512
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001513 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001514 public void onError(int errorCode, String errorMessage) {
1515 super.onError(errorCode, errorMessage);
1516 // TODO: Show error notification to user
1517 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1518 }
1519
1520 }.bind();
1521 } finally {
1522 restoreCallingIdentity(id);
1523 }
1524 }
1525
Amith Yamasani04e0d262012-02-14 11:50:53 -08001526 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001527 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001528 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001529 if (account == null) {
1530 return false;
1531 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001532 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001533 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1534 + " is locked. callingUid=" + callingUid);
1535 return false;
1536 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001537 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001538 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001539 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001540 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001541 Log.w(TAG, "insertAccountIntoDatabase: " + account
1542 + ", skipping since the account already exists");
1543 return false;
1544 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001545 long accountId = accounts.accountsDb.insertCeAccount(account, password);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001546 if (accountId < 0) {
1547 Log.w(TAG, "insertAccountIntoDatabase: " + account
1548 + ", skipping the DB insert failed");
1549 return false;
1550 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001551 // Insert into DE table
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001552 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001553 Log.w(TAG, "insertAccountIntoDatabase: " + account
1554 + ", skipping the DB insert failed");
1555 return false;
1556 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001557 if (extras != null) {
1558 for (String key : extras.keySet()) {
1559 final String value = extras.getString(key);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001560 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001561 Log.w(TAG, "insertAccountIntoDatabase: " + account
1562 + ", skipping since insertExtra failed for key " + key);
1563 return false;
1564 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001565 }
1566 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001567
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001568 if (packageToVisibility != null) {
1569 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1570 setAccountVisibility(account, entry.getKey() /* package */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001571 entry.getValue() /* visibility */, false /* notify */, accounts);
1572 }
1573 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001574 accounts.accountsDb.setTransactionSuccessful();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001575
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001576 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
1577 accounts, callingUid);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001578
Amith Yamasani04e0d262012-02-14 11:50:53 -08001579 insertAccountIntoCacheLocked(accounts, account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001580 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001581 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001582 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001583 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001584 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1585 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001586 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001587
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001588 sendNotification(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001589 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1590 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001591
Amith Yamasani5be347b2013-03-31 17:44:31 -07001592 return true;
1593 }
1594
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001595 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001596 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001597 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001598 }
1599 }
1600
Amith Yamasani5be347b2013-03-31 17:44:31 -07001601 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001602 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001603 * running, then clone the account too.
1604 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001605 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001606 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001607 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001608 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001609 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001610 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001611 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001612 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001613 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001614 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001615 }
1616 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001617 }
1618 }
1619
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001620 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001621 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001622 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001623 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001624 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001625 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1626 Log.v(TAG, "hasFeatures: " + account
1627 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001628 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001629 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001630 + ", pid " + Binder.getCallingPid());
1631 }
Fred Quintana382601f2010-03-25 12:25:10 -07001632 if (response == null) throw new IllegalArgumentException("response is null");
1633 if (account == null) throw new IllegalArgumentException("account is null");
1634 if (features == null) throw new IllegalArgumentException("features is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001635 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001636 checkReadAccountsPermitted(callingUid, account.type, userId,
1637 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001638
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001639 long identityToken = clearCallingIdentity();
1640 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001641 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001642 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001643 } finally {
1644 restoreCallingIdentity(identityToken);
1645 }
1646 }
1647
1648 private class TestFeaturesSession extends Session {
1649 private final String[] mFeatures;
1650 private final Account mAccount;
1651
Amith Yamasani04e0d262012-02-14 11:50:53 -08001652 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001653 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001654 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001655 true /* stripAuthTokenFromResult */, account.name,
1656 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001657 mFeatures = features;
1658 mAccount = account;
1659 }
1660
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001661 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001662 public void run() throws RemoteException {
1663 try {
1664 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1665 } catch (RemoteException e) {
1666 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1667 }
1668 }
1669
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001670 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001671 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001672 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001673 IAccountManagerResponse response = getResponseAndClose();
1674 if (response != null) {
1675 try {
1676 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001677 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001678 return;
1679 }
Fred Quintana56285a62010-12-02 14:20:51 -08001680 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1681 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1682 + response);
1683 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001684 final Bundle newResult = new Bundle();
1685 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1686 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1687 response.onResult(newResult);
1688 } catch (RemoteException e) {
1689 // if the caller is dead then there is no one to care about remote exceptions
1690 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1691 Log.v(TAG, "failure while notifying response", e);
1692 }
1693 }
1694 }
1695 }
1696
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001697 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001698 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001699 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001700 + ", " + mAccount
1701 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1702 }
1703 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001704
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001705 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001706 public void renameAccount(
1707 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001708 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001709 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1710 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001711 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001712 + ", pid " + Binder.getCallingPid());
1713 }
1714 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001715 int userId = UserHandle.getCallingUserId();
1716 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001717 String msg = String.format(
1718 "uid %s cannot rename accounts of type: %s",
1719 callingUid,
1720 accountToRename.type);
1721 throw new SecurityException(msg);
1722 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001723 long identityToken = clearCallingIdentity();
1724 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001725 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001726 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001727 Bundle result = new Bundle();
1728 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1729 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001730 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1731 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001732 try {
1733 response.onResult(result);
1734 } catch (RemoteException e) {
1735 Log.w(TAG, e.getMessage());
1736 }
1737 } finally {
1738 restoreCallingIdentity(identityToken);
1739 }
1740 }
1741
1742 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001743 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001744 Account resultAccount = null;
1745 /*
1746 * Cancel existing notifications. Let authenticators
1747 * re-post notifications as required. But we don't know if
1748 * the authenticators have bound their notifications to
1749 * now stale account name data.
1750 *
1751 * With a rename api, we might not need to do this anymore but it
1752 * shouldn't hurt.
1753 */
1754 cancelNotification(
1755 getSigninRequiredNotificationId(accounts, accountToRename),
1756 new UserHandle(accounts.userId));
1757 synchronized(accounts.credentialsPermissionNotificationIds) {
1758 for (Pair<Pair<Account, String>, Integer> pair:
1759 accounts.credentialsPermissionNotificationIds.keySet()) {
1760 if (accountToRename.equals(pair.first.first)) {
1761 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1762 cancelNotification(id, new UserHandle(accounts.userId));
1763 }
1764 }
1765 }
1766 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001767 accounts.accountsDb.beginTransaction();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001768 Account renamedAccount = new Account(newName, accountToRename.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001769 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1770 Log.e(TAG, "renameAccount failed - account with new name already exists");
1771 return null;
1772 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001773 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001774 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001775 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001776 accounts.accountsDb.renameCeAccount(accountId, newName);
Dmitry Dementyevcf50dcf2016-11-17 14:14:11 -08001777 if (accounts.accountsDb.renameDeAccount(
1778 accountId, newName, accountToRename.name)) {
1779 accounts.accountsDb.setTransactionSuccessful();
1780 } else {
1781 Log.e(TAG, "renameAccount failed");
1782 return null;
1783 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001784 } else {
1785 Log.e(TAG, "renameAccount failed - old account does not exist");
1786 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001787 }
1788 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001789 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001790 }
1791 /*
1792 * Database transaction was successful. Clean up cached
1793 * data associated with the account in the user profile.
1794 */
Svet Ganov5c4a5122016-09-23 19:29:11 -07001795 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001796 /*
1797 * Extract the data and token caches before removing the
1798 * old account to preserve the user data associated with
1799 * the account.
1800 */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001801 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1802 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001803 removeAccountFromCacheLocked(accounts, accountToRename);
1804 /*
1805 * Update the cached data associated with the renamed
1806 * account.
1807 */
1808 accounts.userDataCache.put(renamedAccount, tmpData);
1809 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1810 accounts.previousNameCache.put(
1811 renamedAccount,
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001812 new AtomicReference<>(accountToRename.name));
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001813 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001814
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001815 int parentUserId = accounts.userId;
1816 if (canHaveProfile(parentUserId)) {
1817 /*
1818 * Owner or system user account was renamed, rename the account for
1819 * those users with which the account was shared.
1820 */
1821 List<UserInfo> users = getUserManager().getUsers(true);
1822 for (UserInfo user : users) {
1823 if (user.isRestricted()
1824 && (user.restrictedProfileParentId == parentUserId)) {
1825 renameSharedAccountAsUser(accountToRename, newName, user.id);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001826 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001827 }
1828 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001829
1830 // Notify authenticator.
1831 sendNotification(resultAccount, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001832 sendAccountsChangedBroadcast(accounts.userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001833 }
1834 return resultAccount;
1835 }
1836
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001837 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001838 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001839 return userInfo != null && userInfo.canHaveProfile();
1840 }
1841
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001842 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001843 public void removeAccount(IAccountManagerResponse response, Account account,
1844 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001845 removeAccountAsUser(
1846 response,
1847 account,
1848 expectActivityLaunch,
1849 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001850 }
1851
1852 @Override
1853 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001854 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001855 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001856 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1857 Log.v(TAG, "removeAccount: " + account
1858 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001859 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001860 + ", pid " + Binder.getCallingPid()
1861 + ", for user id " + userId);
1862 }
1863 if (response == null) throw new IllegalArgumentException("response is null");
1864 if (account == null) throw new IllegalArgumentException("account is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001865 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001866 if (isCrossUser(callingUid, userId)) {
1867 throw new SecurityException(
1868 String.format(
1869 "User %s tying remove account for %s" ,
1870 UserHandle.getCallingUserId(),
1871 userId));
1872 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001873 /*
1874 * Only the system or authenticator should be allowed to remove accounts for that
1875 * authenticator. This will let users remove accounts (via Settings in the system) but not
1876 * arbitrary applications (like competing authenticators).
1877 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001878 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00001879 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1880 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001881 String msg = String.format(
1882 "uid %s cannot remove accounts of type: %s",
1883 callingUid,
1884 account.type);
1885 throw new SecurityException(msg);
1886 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001887 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001888 try {
1889 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
1890 "User cannot modify accounts");
1891 } catch (RemoteException re) {
1892 }
1893 return;
1894 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001895 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001896 try {
1897 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
1898 "User cannot modify accounts of this type (policy).");
1899 } catch (RemoteException re) {
1900 }
1901 return;
1902 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001903 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001904 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001905 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001906 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001907 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08001908 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001909 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001910 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001911 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001912 }
1913 }
1914 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001915 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001916 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001917 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1918 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001919 accountId,
1920 accounts,
1921 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001922 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001923 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
1924 } finally {
1925 restoreCallingIdentity(identityToken);
1926 }
1927 }
1928
1929 @Override
1930 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001931 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001932 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1933 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001934 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001935 + ", pid " + Binder.getCallingPid());
1936 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001937 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001938 if (account == null) {
1939 /*
1940 * Null accounts should result in returning false, as per
1941 * AccountManage.addAccountExplicitly(...) java doc.
1942 */
1943 Log.e(TAG, "account is null");
1944 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001945 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001946 String msg = String.format(
1947 "uid %s cannot explicitly add accounts of type: %s",
1948 callingUid,
1949 account.type);
1950 throw new SecurityException(msg);
1951 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001952 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001953 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001954 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001955 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1956 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001957 accountId,
1958 accounts,
1959 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001960 long identityToken = clearCallingIdentity();
1961 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001962 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001963 } finally {
1964 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001965 }
Fred Quintana60307342009-03-24 22:48:12 -07001966 }
1967
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001968 private class RemoveAccountSession extends Session {
1969 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001970 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001971 Account account, boolean expectActivityLaunch) {
1972 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001973 true /* stripAuthTokenFromResult */, account.name,
1974 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001975 mAccount = account;
1976 }
1977
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001978 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001979 protected String toDebugString(long now) {
1980 return super.toDebugString(now) + ", removeAccount"
1981 + ", account " + mAccount;
1982 }
1983
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001984 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001985 public void run() throws RemoteException {
1986 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
1987 }
1988
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001989 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001990 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001991 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001992 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
1993 && !result.containsKey(AccountManager.KEY_INTENT)) {
1994 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001995 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001996 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001997 }
1998 IAccountManagerResponse response = getResponseAndClose();
1999 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002000 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2001 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2002 + response);
2003 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002004 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002005 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002006 try {
2007 response.onResult(result2);
2008 } catch (RemoteException e) {
2009 // ignore
2010 }
2011 }
2012 }
2013 super.onResult(result);
2014 }
2015 }
2016
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002017 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002018 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002019 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002020 }
2021
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002022 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002023 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002024 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002025 if (!userUnlocked) {
2026 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2027 + " is still locked. CE data will be removed later");
2028 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08002029 synchronized (accounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002030 LinkedHashSet<String> interestedPackages =
2031 accounts.mApplicationAccountRequestMappings.get(account.type);
2032 if (interestedPackages == null) {
2033 interestedPackages = new LinkedHashSet<>();
2034 }
2035 int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
2036 int index = 0;
2037 for (String packageName : interestedPackages) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08002038 int visibility = resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002039 visibilityForInterestedPackages[index++] = visibility;
2040 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002041 accounts.accountsDb.beginTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002042 // Set to a dummy value, this will only be used if the database
2043 // transaction succeeds.
2044 long accountId = -1;
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002045 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002046 accountId = accounts.accountsDb.findDeAccountId(account);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002047 if (accountId >= 0) {
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002048 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002049 }
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002050 // always delete from CE table if CE storage is available
2051 // DE account could be removed while CE was locked
2052 if (userUnlocked) {
2053 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2054 if (ceAccountId >= 0) {
2055 accounts.accountsDb.deleteCeAccount(ceAccountId);
2056 }
2057 }
2058 accounts.accountsDb.setTransactionSuccessful();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002059 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002060 accounts.accountsDb.endTransaction();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002061 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002062 if (isChanged) {
2063 removeAccountFromCacheLocked(accounts, account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002064 index = 0;
2065 for (String packageName : interestedPackages) {
2066 if ((visibilityForInterestedPackages[index]
2067 != AccountManager.VISIBILITY_NOT_VISIBLE)
2068 && (visibilityForInterestedPackages[index]
2069 != AccountManager.VISIBILITY_UNDEFINED)) {
2070 sendNotification(packageName, account, accounts.userId);
2071 }
2072 ++index;
2073 }
2074
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002075 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
2076 sendAccountsChangedBroadcast(accounts.userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002077 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2078 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2079 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002080 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002081 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002082 long id = Binder.clearCallingIdentity();
2083 try {
2084 int parentUserId = accounts.userId;
2085 if (canHaveProfile(parentUserId)) {
2086 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002087 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002088 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002089 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002090 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002091 }
2092 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002093 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002094 } finally {
2095 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002096 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002097
2098 if (isChanged) {
2099 synchronized (accounts.credentialsPermissionNotificationIds) {
2100 for (Pair<Pair<Account, String>, Integer> key
2101 : accounts.credentialsPermissionNotificationIds.keySet()) {
2102 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002103 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002104 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002105 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002106 account, uid, false));
2107 }
2108 }
2109 }
2110 }
2111
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002112 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002113 }
2114
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002115 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002116 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002117 int callerUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002118 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2119 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002120 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002121 + ", pid " + Binder.getCallingPid());
2122 }
Fred Quintana382601f2010-03-25 12:25:10 -07002123 if (accountType == null) throw new IllegalArgumentException("accountType is null");
2124 if (authToken == null) throw new IllegalArgumentException("authToken is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002125 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002126 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002127 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002128 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002129 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002130 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002131 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002132 invalidateAuthTokenLocked(accounts, accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002133 invalidateCustomTokenLocked(accounts, accountType, authToken);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002134 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002135 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002136 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002137 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002138 }
Fred Quintana60307342009-03-24 22:48:12 -07002139 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002140 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002141 }
2142 }
2143
Carlos Valdivia91979be2015-05-22 14:11:35 -07002144 private void invalidateCustomTokenLocked(
2145 UserAccounts accounts,
2146 String accountType,
2147 String authToken) {
2148 if (authToken == null || accountType == null) {
2149 return;
2150 }
2151 // Also wipe out cached token in memory.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002152 accounts.accountTokenCaches.remove(accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002153 }
2154
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002155 private void invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
2156 String authToken) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002157 if (authToken == null || accountType == null) {
2158 return;
2159 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002160 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fred Quintana33269202009-04-20 16:05:10 -07002161 try {
2162 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002163 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002164 String accountName = cursor.getString(1);
2165 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002166 accounts.accountsDb.deleteAuthToken(authTokenId);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002167 writeAuthTokenIntoCacheLocked(
2168 accounts,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002169 new Account(accountName, accountType),
2170 authTokenType,
2171 null);
Fred Quintana60307342009-03-24 22:48:12 -07002172 }
Fred Quintana33269202009-04-20 16:05:10 -07002173 } finally {
2174 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002175 }
2176 }
2177
Carlos Valdivia91979be2015-05-22 14:11:35 -07002178 private void saveCachedToken(
2179 UserAccounts accounts,
2180 Account account,
2181 String callerPkg,
2182 byte[] callerSigDigest,
2183 String tokenType,
2184 String token,
2185 long expiryMillis) {
2186
2187 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2188 return;
2189 }
2190 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002191 UserHandle.of(accounts.userId));
Carlos Valdivia91979be2015-05-22 14:11:35 -07002192 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002193 accounts.accountTokenCaches.put(
2194 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002195 }
2196 }
2197
Amith Yamasani04e0d262012-02-14 11:50:53 -08002198 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2199 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002200 if (account == null || type == null) {
2201 return false;
2202 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002203 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002204 UserHandle.of(accounts.userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002205 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002206 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002207 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002208 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002209 if (accountId < 0) {
2210 return false;
2211 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002212 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2213 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2214 accounts.accountsDb.setTransactionSuccessful();
2215 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002216 return true;
2217 }
Fred Quintana33269202009-04-20 16:05:10 -07002218 return false;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002219 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002220 accounts.accountsDb.endTransaction();
Fred Quintana33269202009-04-20 16:05:10 -07002221 }
Fred Quintana60307342009-03-24 22:48:12 -07002222 }
2223 }
2224
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002225 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002226 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002227 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002228 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2229 Log.v(TAG, "peekAuthToken: " + account
2230 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002231 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002232 + ", pid " + Binder.getCallingPid());
2233 }
Fred Quintana382601f2010-03-25 12:25:10 -07002234 if (account == null) throw new IllegalArgumentException("account is null");
2235 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002236 int userId = UserHandle.getCallingUserId();
2237 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002238 String msg = String.format(
2239 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2240 callingUid,
2241 account.type);
2242 throw new SecurityException(msg);
2243 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002244 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002245 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2246 + callingUid);
2247 return null;
2248 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002249 long identityToken = clearCallingIdentity();
2250 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002251 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002252 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002253 } finally {
2254 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002255 }
Fred Quintana60307342009-03-24 22:48:12 -07002256 }
2257
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002258 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002259 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002260 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002261 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2262 Log.v(TAG, "setAuthToken: " + account
2263 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002264 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002265 + ", pid " + Binder.getCallingPid());
2266 }
Fred Quintana382601f2010-03-25 12:25:10 -07002267 if (account == null) throw new IllegalArgumentException("account is null");
2268 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002269 int userId = UserHandle.getCallingUserId();
2270 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002271 String msg = String.format(
2272 "uid %s cannot set auth tokens associated with accounts of type: %s",
2273 callingUid,
2274 account.type);
2275 throw new SecurityException(msg);
2276 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002277 long identityToken = clearCallingIdentity();
2278 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002279 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002280 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002281 } finally {
2282 restoreCallingIdentity(identityToken);
2283 }
Fred Quintana60307342009-03-24 22:48:12 -07002284 }
2285
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002286 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002287 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002288 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002289 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2290 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002291 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002292 + ", pid " + Binder.getCallingPid());
2293 }
Fred Quintana382601f2010-03-25 12:25:10 -07002294 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002295 int userId = UserHandle.getCallingUserId();
2296 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002297 String msg = String.format(
2298 "uid %s cannot set secrets for accounts of type: %s",
2299 callingUid,
2300 account.type);
2301 throw new SecurityException(msg);
2302 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002303 long identityToken = clearCallingIdentity();
2304 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002305 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002306 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002307 } finally {
2308 restoreCallingIdentity(identityToken);
2309 }
Fred Quintana60307342009-03-24 22:48:12 -07002310 }
2311
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002312 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2313 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002314 if (account == null) {
2315 return;
2316 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002317 boolean isChanged = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002318 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002319 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002320 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002321 final long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002322 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002323 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2324 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002325 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002326 accounts.accountTokenCaches.remove(account);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002327 accounts.accountsDb.setTransactionSuccessful();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002328 // If there is an account whose password will be updated and the database
2329 // transactions succeed, then we say that a change has occured. Even if the
2330 // new password is the same as the old and there were no authtokens to delete.
2331 isChanged = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002332 String action = (password == null || password.length() == 0) ?
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002333 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2334 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2335 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
Costin Manolachef5ffe892011-01-19 09:35:32 -08002336 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002337 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002338 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002339 if (isChanged) {
2340 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002341 sendNotification(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002342 sendAccountsChangedBroadcast(accounts.userId);
2343 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002344 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002345 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002346 }
2347
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002348 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002349 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002350 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002351 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2352 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002353 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002354 + ", pid " + Binder.getCallingPid());
2355 }
Fred Quintana382601f2010-03-25 12:25:10 -07002356 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002357 int userId = UserHandle.getCallingUserId();
2358 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002359 String msg = String.format(
2360 "uid %s cannot clear passwords for accounts of type: %s",
2361 callingUid,
2362 account.type);
2363 throw new SecurityException(msg);
2364 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002365 long identityToken = clearCallingIdentity();
2366 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002367 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002368 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002369 } finally {
2370 restoreCallingIdentity(identityToken);
2371 }
Fred Quintana60307342009-03-24 22:48:12 -07002372 }
2373
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002374 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002375 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002376 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002377 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2378 Log.v(TAG, "setUserData: " + account
2379 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002380 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002381 + ", pid " + Binder.getCallingPid());
2382 }
Fred Quintana382601f2010-03-25 12:25:10 -07002383 if (key == null) throw new IllegalArgumentException("key is null");
2384 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002385 int userId = UserHandle.getCallingUserId();
2386 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002387 String msg = String.format(
2388 "uid %s cannot set user data for accounts of type: %s",
2389 callingUid,
2390 account.type);
2391 throw new SecurityException(msg);
2392 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002393 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002394 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002395 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002396 synchronized (accounts.cacheLock) {
2397 if (!accountExistsCacheLocked(accounts, account)) {
2398 return;
2399 }
2400 setUserdataInternalLocked(accounts, account, key, value);
2401 }
Fred Quintana60307342009-03-24 22:48:12 -07002402 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002403 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002404 }
2405 }
2406
Simranjit Kohli858511c2016-03-10 18:36:11 +00002407 private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
2408 if (accounts.accountCache.containsKey(account.type)) {
2409 for (Account acc : accounts.accountCache.get(account.type)) {
2410 if (acc.name.equals(account.name)) {
2411 return true;
2412 }
2413 }
2414 }
2415 return false;
2416 }
2417
2418 private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002419 String value) {
Fred Quintana31957f12009-10-21 13:43:10 -07002420 if (account == null || key == null) {
2421 return;
2422 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002423 accounts.accountsDb.beginTransaction();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002424 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002425 long accountId = accounts.accountsDb.findDeAccountId(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002426 if (accountId < 0) {
2427 return;
2428 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002429 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002430 if (extrasId < 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002431 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002432 if (extrasId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002433 return;
2434 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002435 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002436 return;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002437 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002438 writeUserDataIntoCacheLocked(accounts, account, key, value);
2439 accounts.accountsDb.setTransactionSuccessful();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002440 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002441 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002442 }
2443 }
2444
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002445 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002446 if (result == null) {
2447 Log.e(TAG, "the result is unexpectedly null", new Exception());
2448 }
2449 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2450 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2451 + response);
2452 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002453 try {
2454 response.onResult(result);
2455 } catch (RemoteException e) {
2456 // if the caller is dead then there is no one to care about remote
2457 // exceptions
2458 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2459 Log.v(TAG, "failure while notifying response", e);
2460 }
2461 }
2462 }
2463
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002464 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002465 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2466 final String authTokenType)
2467 throws RemoteException {
2468 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002469 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
2470
Fred Quintanad9640ec2012-05-23 12:37:00 -07002471 final int callingUid = getCallingUid();
2472 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002473 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002474 throw new SecurityException("can only call from system");
2475 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002476 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002477 long identityToken = clearCallingIdentity();
2478 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002479 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002480 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2481 false /* stripAuthTokenFromResult */, null /* accountName */,
2482 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002483 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002484 protected String toDebugString(long now) {
2485 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002486 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002487 + ", authTokenType " + authTokenType;
2488 }
2489
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002490 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002491 public void run() throws RemoteException {
2492 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2493 }
2494
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002495 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002496 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002497 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002498 if (result != null) {
2499 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2500 Bundle bundle = new Bundle();
2501 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2502 super.onResult(bundle);
2503 return;
2504 } else {
2505 super.onResult(result);
2506 }
2507 }
2508 }.bind();
2509 } finally {
2510 restoreCallingIdentity(identityToken);
2511 }
2512 }
2513
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002514 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002515 public void getAuthToken(
2516 IAccountManagerResponse response,
2517 final Account account,
2518 final String authTokenType,
2519 final boolean notifyOnAuthFailure,
2520 final boolean expectActivityLaunch,
2521 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002522 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002523 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2524 Log.v(TAG, "getAuthToken: " + account
2525 + ", response " + response
2526 + ", authTokenType " + authTokenType
2527 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2528 + ", expectActivityLaunch " + expectActivityLaunch
2529 + ", caller's uid " + Binder.getCallingUid()
2530 + ", pid " + Binder.getCallingPid());
2531 }
Fred Quintana382601f2010-03-25 12:25:10 -07002532 if (response == null) throw new IllegalArgumentException("response is null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002533 try {
2534 if (account == null) {
2535 Slog.w(TAG, "getAuthToken called with null account");
2536 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2537 return;
2538 }
2539 if (authTokenType == null) {
2540 Slog.w(TAG, "getAuthToken called with null authTokenType");
2541 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2542 return;
2543 }
2544 } catch (RemoteException e) {
2545 Slog.w(TAG, "Failed to report error back to the client." + e);
2546 return;
2547 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002548 int userId = UserHandle.getCallingUserId();
2549 long ident = Binder.clearCallingIdentity();
2550 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002551 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002552 try {
2553 accounts = getUserAccounts(userId);
2554 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2555 AuthenticatorDescription.newKey(account.type), accounts.userId);
2556 } finally {
2557 Binder.restoreCallingIdentity(ident);
2558 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002559
Costin Manolachea40c6302010-12-13 14:50:45 -08002560 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002561 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002562
2563 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002564 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002565 final boolean permissionGranted =
2566 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002567
Carlos Valdivia91979be2015-05-22 14:11:35 -07002568 // Get the calling package. We will use it for the purpose of caching.
2569 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002570 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002571 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002572 try {
2573 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2574 } finally {
2575 Binder.restoreCallingIdentity(ident);
2576 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002577 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2578 String msg = String.format(
2579 "Uid %s is attempting to illegally masquerade as package %s!",
2580 callerUid,
2581 callerPkg);
2582 throw new SecurityException(msg);
2583 }
2584
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002585 // let authenticator know the identity of the caller
2586 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2587 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002588
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002589 if (notifyOnAuthFailure) {
2590 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002591 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002592
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002593 long identityToken = clearCallingIdentity();
2594 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002595 // Distill the caller's package signatures into a single digest.
2596 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2597
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002598 // if the caller has permission, do the peek. otherwise go the more expensive
2599 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002600 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002601 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002602 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002603 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002604 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2605 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2606 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002607 onResult(response, result);
2608 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002609 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002610 }
2611
Carlos Valdivia91979be2015-05-22 14:11:35 -07002612 if (customTokens) {
2613 /*
2614 * Look up tokens in the new cache only if the loginOptions don't have parameters
2615 * outside of those expected to be injected by the AccountManager, e.g.
2616 * ANDORID_PACKAGE_NAME.
2617 */
2618 String token = readCachedTokenInternal(
2619 accounts,
2620 account,
2621 authTokenType,
2622 callerPkg,
2623 callerPkgSigDigest);
2624 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002625 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2626 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2627 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002628 Bundle result = new Bundle();
2629 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2630 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2631 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2632 onResult(response, result);
2633 return;
2634 }
2635 }
2636
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002637 new Session(
2638 accounts,
2639 response,
2640 account.type,
2641 expectActivityLaunch,
2642 false /* stripAuthTokenFromResult */,
2643 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002644 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002645 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002646 protected String toDebugString(long now) {
2647 if (loginOptions != null) loginOptions.keySet();
2648 return super.toDebugString(now) + ", getAuthToken"
2649 + ", " + account
2650 + ", authTokenType " + authTokenType
2651 + ", loginOptions " + loginOptions
2652 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2653 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002654
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002655 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002656 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002657 // If the caller doesn't have permission then create and return the
2658 // "grant permission" intent instead of the "getAuthToken" intent.
2659 if (!permissionGranted) {
2660 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2661 } else {
2662 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2663 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002664 }
2665
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002666 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002667 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002668 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002669 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002670 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002671 Intent intent = newGrantCredentialsPermissionIntent(
2672 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002673 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002674 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002675 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002676 authTokenType,
2677 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002678 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002679 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002680 onResult(bundle);
2681 return;
2682 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002683 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002684 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002685 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2686 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002687 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002688 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002689 "the type and name should not be empty");
2690 return;
2691 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002692 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002693 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002694 saveAuthTokenToDatabase(
2695 mAccounts,
2696 resultAccount,
2697 authTokenType,
2698 authToken);
2699 }
2700 long expiryMillis = result.getLong(
2701 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2702 if (customTokens
2703 && expiryMillis > System.currentTimeMillis()) {
2704 saveCachedToken(
2705 mAccounts,
2706 account,
2707 callerPkg,
2708 callerPkgSigDigest,
2709 authTokenType,
2710 authToken,
2711 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002712 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002713 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002714
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002715 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002716 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002717 /*
2718 * Make sure that the supplied intent is owned by the authenticator
2719 * giving it to the system. Otherwise a malicious authenticator could
2720 * have users launching arbitrary activities by tricking users to
2721 * interact with malicious notifications.
2722 */
2723 checkKeyIntent(
2724 Binder.getCallingUid(),
2725 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002726 doNotification(
2727 mAccounts,
2728 account,
2729 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002730 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002731 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002732 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002733 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002734 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002735 }.bind();
2736 } finally {
2737 restoreCallingIdentity(identityToken);
2738 }
Fred Quintana60307342009-03-24 22:48:12 -07002739 }
2740
Carlos Valdivia91979be2015-05-22 14:11:35 -07002741 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2742 MessageDigest digester;
2743 try {
2744 digester = MessageDigest.getInstance("SHA-256");
2745 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2746 callerPkg, PackageManager.GET_SIGNATURES);
2747 for (Signature sig : pkgInfo.signatures) {
2748 digester.update(sig.toByteArray());
2749 }
2750 } catch (NoSuchAlgorithmException x) {
2751 Log.wtf(TAG, "SHA-256 should be available", x);
2752 digester = null;
2753 } catch (NameNotFoundException e) {
2754 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2755 digester = null;
2756 }
2757 return (digester == null) ? null : digester.digest();
2758 }
2759
Dianne Hackborn41203752012-08-31 14:05:51 -07002760 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002761 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002762 int uid = intent.getIntExtra(
2763 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2764 String authTokenType = intent.getStringExtra(
2765 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002766 final String titleAndSubtitle =
2767 mContext.getString(R.string.permission_request_notification_with_subtitle,
2768 account.name);
2769 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002770 String title = titleAndSubtitle;
2771 String subtitle = "";
2772 if (index > 0) {
2773 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002774 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002775 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002776 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002777 Context contextForUser = getContextForUser(user);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002778 Notification n = new Notification.Builder(contextForUser)
2779 .setSmallIcon(android.R.drawable.stat_sys_warning)
2780 .setWhen(0)
2781 .setColor(contextForUser.getColor(
2782 com.android.internal.R.color.system_notification_accent_color))
2783 .setContentTitle(title)
2784 .setContentText(subtitle)
2785 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2786 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2787 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002788 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002789 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002790 }
2791
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002792 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2793 int uid, AccountAuthenticatorResponse response, String authTokenType,
2794 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002795
2796 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002797
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002798 if (startInNewTask) {
2799 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2800 // Since it was set in Eclair+ we can't change it without breaking apps using
2801 // the intent from a non-Activity context. This is the default behavior.
2802 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2803 }
2804 intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
2805 authTokenType, uid) + (packageName != null ? packageName : "")));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002806 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002807 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2808 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002809 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002810
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002811 return intent;
2812 }
2813
2814 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2815 int uid) {
2816 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002817 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002818 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002819 final Pair<Pair<Account, String>, Integer> key =
2820 new Pair<Pair<Account, String>, Integer>(
2821 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002822 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002823 if (id == null) {
2824 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002825 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002826 }
2827 }
2828 return id;
2829 }
2830
Amith Yamasani04e0d262012-02-14 11:50:53 -08002831 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002832 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002833 synchronized (accounts.signinRequiredNotificationIds) {
2834 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002835 if (id == null) {
2836 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002837 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002838 }
2839 }
2840 return id;
2841 }
2842
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002843 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002844 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002845 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002846 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002847 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002848 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2849 Log.v(TAG, "addAccount: accountType " + accountType
2850 + ", response " + response
2851 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002852 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002853 + ", expectActivityLaunch " + expectActivityLaunch
2854 + ", caller's uid " + Binder.getCallingUid()
2855 + ", pid " + Binder.getCallingPid());
2856 }
Fred Quintana382601f2010-03-25 12:25:10 -07002857 if (response == null) throw new IllegalArgumentException("response is null");
2858 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002859
Amith Yamasani71e6c692013-03-24 17:39:28 -07002860 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002861 final int uid = Binder.getCallingUid();
2862 final int userId = UserHandle.getUserId(uid);
2863 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002864 try {
2865 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2866 "User is not allowed to add an account!");
2867 } catch (RemoteException re) {
2868 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002869 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002870 return;
2871 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002872 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002873 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002874 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2875 "User cannot modify accounts of this type (policy).");
2876 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002877 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002878 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2879 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002880 return;
2881 }
2882
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002883 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002884 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2885 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2886 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2887
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002888 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002889 long identityToken = clearCallingIdentity();
2890 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002891 UserAccounts accounts = getUserAccounts(usrId);
2892 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002893 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2894 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002895 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002896 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002897 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002898 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002899 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07002900 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07002901 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002902 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002903
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002904 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002905 protected String toDebugString(long now) {
2906 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07002907 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002908 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002909 }
2910 }.bind();
2911 } finally {
2912 restoreCallingIdentity(identityToken);
2913 }
Fred Quintana60307342009-03-24 22:48:12 -07002914 }
2915
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002916 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002917 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
2918 final String authTokenType, final String[] requiredFeatures,
2919 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002920 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002921 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002922 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2923 Log.v(TAG, "addAccount: accountType " + accountType
2924 + ", response " + response
2925 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002926 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002927 + ", expectActivityLaunch " + expectActivityLaunch
2928 + ", caller's uid " + Binder.getCallingUid()
2929 + ", pid " + Binder.getCallingPid()
2930 + ", for user id " + userId);
2931 }
2932 if (response == null) throw new IllegalArgumentException("response is null");
2933 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002934 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002935 if (isCrossUser(callingUid, userId)) {
2936 throw new SecurityException(
2937 String.format(
2938 "User %s trying to add account for %s" ,
2939 UserHandle.getCallingUserId(),
2940 userId));
2941 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002942
2943 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002944 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002945 try {
2946 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2947 "User is not allowed to add an account!");
2948 } catch (RemoteException re) {
2949 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002950 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002951 return;
2952 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002953 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002954 try {
2955 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2956 "User cannot modify accounts of this type (policy).");
2957 } catch (RemoteException re) {
2958 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002959 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2960 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002961 return;
2962 }
2963
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002964 final int pid = Binder.getCallingPid();
2965 final int uid = Binder.getCallingUid();
2966 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2967 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2968 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2969
2970 long identityToken = clearCallingIdentity();
2971 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002972 UserAccounts accounts = getUserAccounts(userId);
2973 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002974 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2975 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002976 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002977 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002978 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002979 @Override
2980 public void run() throws RemoteException {
2981 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
2982 options);
2983 }
2984
2985 @Override
2986 protected String toDebugString(long now) {
2987 return super.toDebugString(now) + ", addAccount"
2988 + ", accountType " + accountType
2989 + ", requiredFeatures "
2990 + (requiredFeatures != null
2991 ? TextUtils.join(",", requiredFeatures)
2992 : null);
2993 }
2994 }.bind();
2995 } finally {
2996 restoreCallingIdentity(identityToken);
2997 }
2998 }
2999
Sandra Kwan78812282015-11-04 11:19:47 -08003000 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003001 public void startAddAccountSession(
3002 final IAccountManagerResponse response,
3003 final String accountType,
3004 final String authTokenType,
3005 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003006 final boolean expectActivityLaunch,
3007 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003008 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003009 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3010 Log.v(TAG,
3011 "startAddAccountSession: accountType " + accountType
3012 + ", response " + response
3013 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003014 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003015 + ", expectActivityLaunch " + expectActivityLaunch
3016 + ", caller's uid " + Binder.getCallingUid()
3017 + ", pid " + Binder.getCallingPid());
3018 }
3019 if (response == null) {
3020 throw new IllegalArgumentException("response is null");
3021 }
3022 if (accountType == null) {
3023 throw new IllegalArgumentException("accountType is null");
3024 }
3025
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003026 final int uid = Binder.getCallingUid();
3027 final int userId = UserHandle.getUserId(uid);
3028 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003029 try {
3030 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3031 "User is not allowed to add an account!");
3032 } catch (RemoteException re) {
3033 }
3034 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3035 return;
3036 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003037 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003038 try {
3039 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3040 "User cannot modify accounts of this type (policy).");
3041 } catch (RemoteException re) {
3042 }
3043 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3044 userId);
3045 return;
3046 }
Sandra Kwan78812282015-11-04 11:19:47 -08003047 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003048 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3049 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3050 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3051
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003052 // Check to see if the Password should be included to the caller.
3053 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3054 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003055 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003056
Sandra Kwan78812282015-11-04 11:19:47 -08003057 long identityToken = clearCallingIdentity();
3058 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003059 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003060 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3061 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003062 new StartAccountSession(
3063 accounts,
3064 response,
3065 accountType,
3066 expectActivityLaunch,
3067 null /* accountName */,
3068 false /* authDetailsRequired */,
3069 true /* updateLastAuthenticationTime */,
3070 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003071 @Override
3072 public void run() throws RemoteException {
3073 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3074 requiredFeatures, options);
3075 }
3076
3077 @Override
3078 protected String toDebugString(long now) {
3079 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3080 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3081 + accountType + ", requiredFeatures "
3082 + (requiredFeatures != null ? requiredFeaturesStr : null);
3083 }
3084 }.bind();
3085 } finally {
3086 restoreCallingIdentity(identityToken);
3087 }
3088 }
3089
3090 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3091 private abstract class StartAccountSession extends Session {
3092
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003093 private final boolean mIsPasswordForwardingAllowed;
3094
3095 public StartAccountSession(
3096 UserAccounts accounts,
3097 IAccountManagerResponse response,
3098 String accountType,
3099 boolean expectActivityLaunch,
3100 String accountName,
3101 boolean authDetailsRequired,
3102 boolean updateLastAuthenticationTime,
3103 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003104 super(accounts, response, accountType, expectActivityLaunch,
3105 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3106 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003107 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003108 }
3109
3110 @Override
3111 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003112 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003113 mNumResults++;
3114 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003115 if (result != null
3116 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003117 checkKeyIntent(
3118 Binder.getCallingUid(),
3119 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003120 }
Sandra Kwan78812282015-11-04 11:19:47 -08003121 IAccountManagerResponse response;
3122 if (mExpectActivityLaunch && result != null
3123 && result.containsKey(AccountManager.KEY_INTENT)) {
3124 response = mResponse;
3125 } else {
3126 response = getResponseAndClose();
3127 }
3128 if (response == null) {
3129 return;
3130 }
3131 if (result == null) {
3132 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3133 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3134 + response);
3135 }
3136 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3137 "null bundle returned");
3138 return;
3139 }
3140
3141 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3142 // All AccountManager error codes are greater
3143 // than 0
3144 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3145 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3146 return;
3147 }
3148
Hongming Jin368aa192016-07-29 14:29:54 -07003149 // Omit passwords if the caller isn't permitted to see them.
3150 if (!mIsPasswordForwardingAllowed) {
3151 result.remove(AccountManager.KEY_PASSWORD);
3152 }
3153
Sandra Kwan78812282015-11-04 11:19:47 -08003154 // Strip auth token from result.
3155 result.remove(AccountManager.KEY_AUTHTOKEN);
3156
3157 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3158 Log.v(TAG,
3159 getClass().getSimpleName() + " calling onResult() on response " + response);
3160 }
3161
3162 // Get the session bundle created by authenticator. The
3163 // bundle contains data necessary for finishing the session
3164 // later. The session bundle will be encrypted here and
3165 // decrypted later when trying to finish the session.
3166 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3167 if (sessionBundle != null) {
3168 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3169 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003170 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003171 Log.w(TAG, "Account type in session bundle doesn't match request.");
3172 }
3173 // Add accountType info to session bundle. This will
3174 // override any value set by authenticator.
3175 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3176
3177 // Encrypt session bundle before returning to caller.
3178 try {
3179 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3180 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3181 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3182 } catch (GeneralSecurityException e) {
3183 if (Log.isLoggable(TAG, Log.DEBUG)) {
3184 Log.v(TAG, "Failed to encrypt session bundle!", e);
3185 }
3186 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3187 "failed to encrypt session bundle");
3188 return;
3189 }
3190 }
3191
3192 sendResponse(response, result);
3193 }
3194 }
3195
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003196 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003197 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003198 @NonNull Bundle sessionBundle,
3199 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003200 Bundle appInfo,
3201 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003202 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003203 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003204 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3205 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003206 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003207 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003208 + ", caller's uid " + callingUid
3209 + ", caller's user id " + UserHandle.getCallingUserId()
3210 + ", pid " + Binder.getCallingPid()
3211 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003212 }
3213 if (response == null) {
3214 throw new IllegalArgumentException("response is null");
3215 }
3216
3217 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3218 // Account type is added to it before encryption.
3219 if (sessionBundle == null || sessionBundle.size() == 0) {
3220 throw new IllegalArgumentException("sessionBundle is empty");
3221 }
3222
Dmitry Dementyev52745472016-12-02 10:27:45 -08003223 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003224 if (isCrossUser(callingUid, userId)) {
3225 throw new SecurityException(
3226 String.format(
3227 "User %s trying to finish session for %s without cross user permission",
3228 UserHandle.getCallingUserId(),
3229 userId));
3230 }
3231
Sandra Kwan0b84b452016-01-20 15:25:42 -08003232 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003233 sendErrorResponse(response,
3234 AccountManager.ERROR_CODE_USER_RESTRICTED,
3235 "User is not allowed to add an account!");
3236 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3237 return;
3238 }
3239
3240 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003241 final Bundle decryptedBundle;
3242 final String accountType;
3243 // First decrypt session bundle to get account type for checking permission.
3244 try {
3245 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3246 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3247 if (decryptedBundle == null) {
3248 sendErrorResponse(
3249 response,
3250 AccountManager.ERROR_CODE_BAD_REQUEST,
3251 "failed to decrypt session bundle");
3252 return;
3253 }
3254 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3255 // Account type cannot be null. This should not happen if session bundle was created
3256 // properly by #StartAccountSession.
3257 if (TextUtils.isEmpty(accountType)) {
3258 sendErrorResponse(
3259 response,
3260 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3261 "accountType is empty");
3262 return;
3263 }
3264
3265 // If by any chances, decryptedBundle contains colliding keys with
3266 // system info
3267 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3268 // update credentials flow, we should replace with the new values of the current call.
3269 if (appInfo != null) {
3270 decryptedBundle.putAll(appInfo);
3271 }
3272
3273 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003274 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003275 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3276 } catch (GeneralSecurityException e) {
3277 if (Log.isLoggable(TAG, Log.DEBUG)) {
3278 Log.v(TAG, "Failed to decrypt session bundle!", e);
3279 }
3280 sendErrorResponse(
3281 response,
3282 AccountManager.ERROR_CODE_BAD_REQUEST,
3283 "failed to decrypt session bundle");
3284 return;
3285 }
3286
Sandra Kwan0b84b452016-01-20 15:25:42 -08003287 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003288 sendErrorResponse(
3289 response,
3290 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3291 "User cannot modify accounts of this type (policy).");
3292 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3293 userId);
3294 return;
3295 }
3296
3297 long identityToken = clearCallingIdentity();
3298 try {
3299 UserAccounts accounts = getUserAccounts(userId);
3300 logRecordWithUid(
3301 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003302 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3303 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003304 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003305 new Session(
3306 accounts,
3307 response,
3308 accountType,
3309 expectActivityLaunch,
3310 true /* stripAuthTokenFromResult */,
3311 null /* accountName */,
3312 false /* authDetailsRequired */,
3313 true /* updateLastAuthenticationTime */) {
3314 @Override
3315 public void run() throws RemoteException {
3316 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3317 }
3318
3319 @Override
3320 protected String toDebugString(long now) {
3321 return super.toDebugString(now)
3322 + ", finishSession"
3323 + ", accountType " + accountType;
3324 }
3325 }.bind();
3326 } finally {
3327 restoreCallingIdentity(identityToken);
3328 }
3329 }
3330
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003331 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003332 final DevicePolicyManagerInternal dpmi =
3333 LocalServices.getService(DevicePolicyManagerInternal.class);
3334 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003335 if (dpmi == null) {
3336 intent = getDefaultCantAddAccountIntent(errorCode);
3337 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003338 intent = dpmi.createUserRestrictionSupportIntent(userId,
3339 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3340 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3341 intent = dpmi.createShowAdminSupportIntent(userId, false);
3342 }
3343 if (intent == null) {
3344 intent = getDefaultCantAddAccountIntent(errorCode);
3345 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003346 long identityToken = clearCallingIdentity();
3347 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003348 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003349 } finally {
3350 restoreCallingIdentity(identityToken);
3351 }
3352 }
3353
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003354 /**
3355 * Called when we don't know precisely who is preventing us from adding an account.
3356 */
3357 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3358 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3359 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3360 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3361 return cantAddAccount;
3362 }
3363
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003364 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003365 public void confirmCredentialsAsUser(
3366 IAccountManagerResponse response,
3367 final Account account,
3368 final Bundle options,
3369 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003370 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003371 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003372 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003373 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3374 Log.v(TAG, "confirmCredentials: " + account
3375 + ", response " + response
3376 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003377 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003378 + ", pid " + Binder.getCallingPid());
3379 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003380 // Only allow the system process to read accounts of other users
3381 if (isCrossUser(callingUid, userId)) {
3382 throw new SecurityException(
3383 String.format(
3384 "User %s trying to confirm account credentials for %s" ,
3385 UserHandle.getCallingUserId(),
3386 userId));
3387 }
Fred Quintana382601f2010-03-25 12:25:10 -07003388 if (response == null) throw new IllegalArgumentException("response is null");
3389 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003390 long identityToken = clearCallingIdentity();
3391 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003392 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003393 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003394 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003395 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003396 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003397 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003398 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003399 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003400 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003401 protected String toDebugString(long now) {
3402 return super.toDebugString(now) + ", confirmCredentials"
3403 + ", " + account;
3404 }
3405 }.bind();
3406 } finally {
3407 restoreCallingIdentity(identityToken);
3408 }
Fred Quintana60307342009-03-24 22:48:12 -07003409 }
3410
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003411 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003412 public void updateCredentials(IAccountManagerResponse response, final Account account,
3413 final String authTokenType, final boolean expectActivityLaunch,
3414 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003415 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003416 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3417 Log.v(TAG, "updateCredentials: " + account
3418 + ", response " + response
3419 + ", authTokenType " + authTokenType
3420 + ", expectActivityLaunch " + expectActivityLaunch
3421 + ", caller's uid " + Binder.getCallingUid()
3422 + ", pid " + Binder.getCallingPid());
3423 }
Fred Quintana382601f2010-03-25 12:25:10 -07003424 if (response == null) throw new IllegalArgumentException("response is null");
3425 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003426 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003427 long identityToken = clearCallingIdentity();
3428 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003429 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003430 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003431 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003432 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003433 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003434 public void run() throws RemoteException {
3435 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3436 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003437 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003438 protected String toDebugString(long now) {
3439 if (loginOptions != null) loginOptions.keySet();
3440 return super.toDebugString(now) + ", updateCredentials"
3441 + ", " + account
3442 + ", authTokenType " + authTokenType
3443 + ", loginOptions " + loginOptions;
3444 }
3445 }.bind();
3446 } finally {
3447 restoreCallingIdentity(identityToken);
3448 }
Fred Quintana60307342009-03-24 22:48:12 -07003449 }
3450
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003451 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003452 public void startUpdateCredentialsSession(
3453 IAccountManagerResponse response,
3454 final Account account,
3455 final String authTokenType,
3456 final boolean expectActivityLaunch,
3457 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003458 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003459 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3460 Log.v(TAG,
3461 "startUpdateCredentialsSession: " + account + ", response " + response
3462 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3463 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3464 + ", pid " + Binder.getCallingPid());
3465 }
3466 if (response == null) {
3467 throw new IllegalArgumentException("response is null");
3468 }
3469 if (account == null) {
3470 throw new IllegalArgumentException("account is null");
3471 }
Sandra Kwana578d112015-12-16 16:01:43 -08003472
3473 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003474 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003475
3476 // Check to see if the Password should be included to the caller.
3477 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3478 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003479 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003480
Sandra Kwane68c37e2015-11-12 17:11:49 -08003481 long identityToken = clearCallingIdentity();
3482 try {
3483 UserAccounts accounts = getUserAccounts(userId);
3484 new StartAccountSession(
3485 accounts,
3486 response,
3487 account.type,
3488 expectActivityLaunch,
3489 account.name,
3490 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003491 true /* updateLastCredentialTime */,
3492 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003493 @Override
3494 public void run() throws RemoteException {
3495 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3496 loginOptions);
3497 }
3498
3499 @Override
3500 protected String toDebugString(long now) {
3501 if (loginOptions != null)
3502 loginOptions.keySet();
3503 return super.toDebugString(now)
3504 + ", startUpdateCredentialsSession"
3505 + ", " + account
3506 + ", authTokenType " + authTokenType
3507 + ", loginOptions " + loginOptions;
3508 }
3509 }.bind();
3510 } finally {
3511 restoreCallingIdentity(identityToken);
3512 }
3513 }
3514
3515 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003516 public void isCredentialsUpdateSuggested(
3517 IAccountManagerResponse response,
3518 final Account account,
3519 final String statusToken) {
3520 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3521 Log.v(TAG,
3522 "isCredentialsUpdateSuggested: " + account + ", response " + response
3523 + ", caller's uid " + Binder.getCallingUid()
3524 + ", pid " + Binder.getCallingPid());
3525 }
3526 if (response == null) {
3527 throw new IllegalArgumentException("response is null");
3528 }
3529 if (account == null) {
3530 throw new IllegalArgumentException("account is null");
3531 }
3532 if (TextUtils.isEmpty(statusToken)) {
3533 throw new IllegalArgumentException("status token is empty");
3534 }
3535
Sandra Kwan390c9d22016-01-12 14:13:37 -08003536 int usrId = UserHandle.getCallingUserId();
3537 long identityToken = clearCallingIdentity();
3538 try {
3539 UserAccounts accounts = getUserAccounts(usrId);
3540 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3541 false /* stripAuthTokenFromResult */, account.name,
3542 false /* authDetailsRequired */) {
3543 @Override
3544 protected String toDebugString(long now) {
3545 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3546 + ", " + account;
3547 }
3548
3549 @Override
3550 public void run() throws RemoteException {
3551 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3552 }
3553
3554 @Override
3555 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003556 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003557 IAccountManagerResponse response = getResponseAndClose();
3558 if (response == null) {
3559 return;
3560 }
3561
3562 if (result == null) {
3563 sendErrorResponse(
3564 response,
3565 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3566 "null bundle");
3567 return;
3568 }
3569
3570 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3571 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3572 + response);
3573 }
3574 // Check to see if an error occurred. We know if an error occurred because all
3575 // error codes are greater than 0.
3576 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3577 sendErrorResponse(response,
3578 result.getInt(AccountManager.KEY_ERROR_CODE),
3579 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3580 return;
3581 }
3582 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3583 sendErrorResponse(
3584 response,
3585 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3586 "no result in response");
3587 return;
3588 }
3589 final Bundle newResult = new Bundle();
3590 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3591 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3592 sendResponse(response, newResult);
3593 }
3594 }.bind();
3595 } finally {
3596 restoreCallingIdentity(identityToken);
3597 }
3598 }
3599
3600 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003601 public void editProperties(IAccountManagerResponse response, final String accountType,
3602 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003603 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003604 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3605 Log.v(TAG, "editProperties: accountType " + accountType
3606 + ", response " + response
3607 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003608 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003609 + ", pid " + Binder.getCallingPid());
3610 }
Fred Quintana382601f2010-03-25 12:25:10 -07003611 if (response == null) throw new IllegalArgumentException("response is null");
3612 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003613 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003614 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3615 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003616 String msg = String.format(
3617 "uid %s cannot edit authenticator properites for account type: %s",
3618 callingUid,
3619 accountType);
3620 throw new SecurityException(msg);
3621 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003622 long identityToken = clearCallingIdentity();
3623 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003624 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003625 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003626 true /* stripAuthTokenFromResult */, null /* accountName */,
3627 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003628 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003629 public void run() throws RemoteException {
3630 mAuthenticator.editProperties(this, mAccountType);
3631 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003632 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003633 protected String toDebugString(long now) {
3634 return super.toDebugString(now) + ", editProperties"
3635 + ", accountType " + accountType;
3636 }
3637 }.bind();
3638 } finally {
3639 restoreCallingIdentity(identityToken);
3640 }
Fred Quintana60307342009-03-24 22:48:12 -07003641 }
3642
Amith Yamasani12747872015-12-07 14:19:49 -08003643 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003644 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3645 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003646 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003647 throw new SecurityException("Can be called only by system UID");
3648 }
3649 Preconditions.checkNotNull(account, "account cannot be null");
3650 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3651 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3652
3653 final int userId = userHandle.getIdentifier();
3654
3655 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3656
3657 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003658 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003659 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003660 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003661 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003662 return false;
3663 }
3664 }
3665
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003666 // Returns package with oldest target SDK for given UID.
3667 private String getPackageNameForUid(int uid) {
3668 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3669 if (ArrayUtils.isEmpty(packageNames)) {
3670 return null;
3671 }
3672 // For app op checks related to permissions all packages in the UID
3673 // have the same app op state, so doesn't matter which one we pick.
3674 // Update: due to visibility changes we want to use package with oldest target SDK,
3675
3676 String packageName = packageNames[0];
3677 int oldestVersion = Integer.MAX_VALUE;
3678 for (String name : packageNames) {
3679 try {
3680 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3681 if (applicationInfo != null) {
3682 int version = applicationInfo.targetSdkVersion;
3683 if (version < oldestVersion) {
3684 oldestVersion = version;
3685 packageName = name;
3686 }
3687 }
3688 } catch (NameNotFoundException e) {
3689 // skip
3690 }
3691 }
3692 return packageName;
3693 }
3694
Svet Ganovf6d424f12016-09-20 20:18:53 -07003695 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3696 int uid) {
3697 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003698 packageName = getPackageNameForUid(uid);
3699 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003700 return false;
3701 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003702 }
3703
3704 // Use null token which means any token. Having a token means the package
3705 // is trusted by the authenticator, hence it is fine to access the account.
3706 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3707 return true;
3708 }
3709 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003710 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003711
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003712 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003713 getUserAccounts(UserHandle.getUserId(uid)));
3714 return (visibility == AccountManager.VISIBILITY_VISIBLE
3715 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003716 }
3717
3718 @Override
3719 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3720 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003721 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003722 throw new SecurityException("Can be called only by system UID");
3723 }
3724
3725 Preconditions.checkNotNull(account, "account cannot be null");
3726 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3727 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3728
3729 final int userId = userHandle.getIdentifier();
3730
3731 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3732
3733 final int uid;
3734 try {
3735 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3736 } catch (NameNotFoundException e) {
3737 Slog.e(TAG, "Unknown package " + packageName);
3738 return null;
3739 }
3740
3741 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3742
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003743 final long identity = Binder.clearCallingIdentity();
3744 try {
3745 return PendingIntent.getActivityAsUser(
3746 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3747 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3748 null, new UserHandle(userId)).getIntentSender();
3749 } finally {
3750 Binder.restoreCallingIdentity(identity);
3751 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003752 }
3753
3754 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3755 int uid, RemoteCallback callback) {
3756 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3757 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3758 @Override
3759 public void onResult(Bundle value) throws RemoteException {
3760 handleAuthenticatorResponse(true);
3761 }
3762
3763 @Override
3764 public void onRequestContinued() {
3765 /* ignore */
3766 }
3767
3768 @Override
3769 public void onError(int errorCode, String errorMessage) throws RemoteException {
3770 handleAuthenticatorResponse(false);
3771 }
3772
3773 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3774 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003775 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003776 UserHandle.getUserHandleForUid(uid));
3777 if (callback != null) {
3778 Bundle result = new Bundle();
3779 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3780 callback.sendResult(result);
3781 }
3782 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003783 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003784 }
3785
3786 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003787 public boolean someUserHasAccount(@NonNull final Account account) {
3788 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3789 throw new SecurityException("Only system can check for accounts across users");
3790 }
3791 final long token = Binder.clearCallingIdentity();
3792 try {
3793 AccountAndUser[] allAccounts = getAllAccounts();
3794 for (int i = allAccounts.length - 1; i >= 0; i--) {
3795 if (allAccounts[i].account.equals(account)) {
3796 return true;
3797 }
3798 }
3799 return false;
3800 } finally {
3801 Binder.restoreCallingIdentity(token);
3802 }
3803 }
3804
Fred Quintana33269202009-04-20 16:05:10 -07003805 private class GetAccountsByTypeAndFeatureSession extends Session {
3806 private final String[] mFeatures;
3807 private volatile Account[] mAccountsOfType = null;
3808 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3809 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003810 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003811 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003812
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003813 public GetAccountsByTypeAndFeatureSession(
3814 UserAccounts accounts,
3815 IAccountManagerResponse response,
3816 String type,
3817 String[] features,
3818 int callingUid,
3819 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003820 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003821 true /* stripAuthTokenFromResult */, null /* accountName */,
3822 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003823 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003824 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003825 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003826 }
3827
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003828 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003829 public void run() throws RemoteException {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003830 synchronized (mAccounts.cacheLock) {
Amith Yamasani27db4682013-03-30 17:07:47 -07003831 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003832 mPackageName, false /* include managed not visible*/);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003833 }
Fred Quintana33269202009-04-20 16:05:10 -07003834 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003835 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003836 mCurrentAccount = 0;
3837
3838 checkAccount();
3839 }
3840
3841 public void checkAccount() {
3842 if (mCurrentAccount >= mAccountsOfType.length) {
3843 sendResult();
3844 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003845 }
Fred Quintana33269202009-04-20 16:05:10 -07003846
Fred Quintana29e94b82010-03-10 12:11:51 -08003847 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3848 if (accountAuthenticator == null) {
3849 // It is possible that the authenticator has died, which is indicated by
3850 // mAuthenticator being set to null. If this happens then just abort.
3851 // There is no need to send back a result or error in this case since
3852 // that already happened when mAuthenticator was cleared.
3853 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3854 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3855 + " connected to the authenticator, " + toDebugString());
3856 }
3857 return;
3858 }
Fred Quintana33269202009-04-20 16:05:10 -07003859 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003860 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003861 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003862 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003863 }
3864 }
3865
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003866 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003867 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003868 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003869 mNumResults++;
3870 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003871 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003872 return;
3873 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003874 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003875 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3876 }
3877 mCurrentAccount++;
3878 checkAccount();
3879 }
3880
3881 public void sendResult() {
3882 IAccountManagerResponse response = getResponseAndClose();
3883 if (response != null) {
3884 try {
3885 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3886 for (int i = 0; i < accounts.length; i++) {
3887 accounts[i] = mAccountsWithFeatures.get(i);
3888 }
Fred Quintana56285a62010-12-02 14:20:51 -08003889 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3890 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3891 + response);
3892 }
Fred Quintana33269202009-04-20 16:05:10 -07003893 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003894 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07003895 response.onResult(result);
3896 } catch (RemoteException e) {
3897 // if the caller is dead then there is no one to care about remote exceptions
3898 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3899 Log.v(TAG, "failure while notifying response", e);
3900 }
3901 }
3902 }
3903 }
3904
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003905 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003906 protected String toDebugString(long now) {
3907 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
3908 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
3909 }
3910 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07003911
Amith Yamasani04e0d262012-02-14 11:50:53 -08003912 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003913 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08003914 * @hide
3915 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003916 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07003917 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003918 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003919 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07003920 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
3921 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003922 if (visibleAccountTypes.isEmpty()) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003923 return new Account[0];
3924 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003925 long identityToken = clearCallingIdentity();
3926 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003927 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003928 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003929 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003930 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003931 opPackageName,
3932 visibleAccountTypes,
3933 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003934 } finally {
3935 restoreCallingIdentity(identityToken);
3936 }
3937 }
3938
Amith Yamasanif29f2362012-04-05 18:29:52 -07003939 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003940 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003941 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07003942 * @hide
3943 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003944 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003945 public AccountAndUser[] getRunningAccounts() {
3946 final int[] runningUserIds;
3947 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08003948 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003949 } catch (RemoteException e) {
3950 // Running in system_server; should never happen
3951 throw new RuntimeException(e);
3952 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003953 return getAccounts(runningUserIds);
3954 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07003955
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003956 /**
3957 * Returns accounts for all users, ignores visibility values.
3958 *
3959 * @hide
3960 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003961 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003962 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07003963 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003964 final int[] userIds = new int[users.size()];
3965 for (int i = 0; i < userIds.length; i++) {
3966 userIds[i] = users.get(i).id;
3967 }
3968 return getAccounts(userIds);
3969 }
3970
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003971 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003972 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003973 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07003974 for (int userId : userIds) {
3975 UserAccounts userAccounts = getUserAccounts(userId);
3976 if (userAccounts == null) continue;
3977 synchronized (userAccounts.cacheLock) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003978 Account[] accounts = getAccountsFromCacheLocked(
3979 userAccounts,
3980 null /* type */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003981 Binder.getCallingUid(),
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003982 null /* packageName */,
3983 false /* include managed not visible*/);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07003984 for (int a = 0; a < accounts.length; a++) {
3985 runningAccounts.add(new AccountAndUser(accounts[a], userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07003986 }
3987 }
3988 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003989
3990 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
3991 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07003992 }
3993
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003994 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003995 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07003996 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003997 int callingUid = Binder.getCallingUid();
3998 mAppOpsManager.checkPackage(callingUid, opPackageName);
3999 return getAccountsAsUser(type, userId, opPackageName /* callingPackage */, -1,
4000 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004001 }
4002
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004003 @NonNull
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004004 private Account[] getAccountsAsUser(
4005 String type,
4006 int userId,
4007 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004008 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004009 String opPackageName,
4010 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004011 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004012 // Only allow the system process to read accounts of other users
4013 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004014 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004015 && mContext.checkCallingOrSelfPermission(
4016 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4017 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004018 throw new SecurityException("User " + UserHandle.getCallingUserId()
4019 + " trying to get account for " + userId);
4020 }
4021
Fred Quintana56285a62010-12-02 14:20:51 -08004022 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4023 Log.v(TAG, "getAccounts: accountType " + type
4024 + ", caller's uid " + Binder.getCallingUid()
4025 + ", pid " + Binder.getCallingPid());
4026 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004027
4028 // If the original calling app was using account choosing activity
4029 // provided by the framework or authenticator we'll passing in
4030 // the original caller's uid here, which is what should be used for filtering.
4031 List<String> managedTypes =
4032 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4033 if (packageUid != -1 &&
4034 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4035 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004036 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004037 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004038 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004039 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4040 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004041 if (visibleAccountTypes.isEmpty()
4042 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004043 return new Account[]{};
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004044 } else if (visibleAccountTypes.contains(type)) {
4045 // Prune the list down to just the requested type.
4046 visibleAccountTypes = new ArrayList<>();
4047 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004048 } // else aggregate all the visible accounts (it won't matter if the
4049 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004050
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004051 long identityToken = clearCallingIdentity();
4052 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004053 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004054 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004055 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004056 callingUid,
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00004057 callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004058 visibleAccountTypes,
4059 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004060 } finally {
4061 restoreCallingIdentity(identityToken);
4062 }
4063 }
4064
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004065 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004066 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004067 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004068 int callingUid,
4069 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004070 List<String> visibleAccountTypes,
4071 boolean includeUserManagedNotVisible) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004072 synchronized (userAccounts.cacheLock) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004073 ArrayList<Account> visibleAccounts = new ArrayList<>();
4074 for (String visibleType : visibleAccountTypes) {
4075 Account[] accountsForType = getAccountsFromCacheLocked(
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004076 userAccounts, visibleType, callingUid, callingPackage,
4077 includeUserManagedNotVisible);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004078 if (accountsForType != null) {
4079 visibleAccounts.addAll(Arrays.asList(accountsForType));
4080 }
4081 }
4082 Account[] result = new Account[visibleAccounts.size()];
4083 for (int i = 0; i < visibleAccounts.size(); i++) {
4084 result[i] = visibleAccounts.get(i);
4085 }
4086 return result;
4087 }
4088 }
4089
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004090 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004091 public void addSharedAccountsFromParentUser(int parentUserId, int userId) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004092 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004093 Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName());
4094 for (Account account : accounts) {
4095 addSharedAccountAsUser(account, userId);
4096 }
4097 }
4098
4099 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004100 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004101 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004102 accounts.accountsDb.deleteSharedAccount(account);
4103 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004104 if (accountId < 0) {
4105 Log.w(TAG, "insertAccountIntoDatabase: " + account
4106 + ", skipping the DB insert failed");
4107 return false;
4108 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004109 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4110 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004111 return true;
4112 }
4113
4114 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004115 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4116 userId = handleIncomingUser(userId);
4117 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004118 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4119 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004120 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004121 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004122 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004123 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004124 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004125 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004126 }
4127 return r > 0;
4128 }
4129
4130 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004131 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004132 return removeSharedAccountAsUser(account, userId, getCallingUid());
4133 }
4134
4135 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004136 userId = handleIncomingUser(userId);
4137 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004138 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4139 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004140 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004141 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004142 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004143 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004144 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004145 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004146 }
4147
4148 @Override
4149 public Account[] getSharedAccountsAsUser(int userId) {
4150 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004151 UserAccounts accounts = getUserAccounts(userId);
4152 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004153 Account[] accountArray = new Account[accountList.size()];
4154 accountList.toArray(accountArray);
4155 return accountArray;
4156 }
4157
4158 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004159 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004160 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004161 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004162 }
4163
Amith Yamasani27db4682013-03-30 17:07:47 -07004164 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004165 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004166 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004167 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004168 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004169 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004170 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4171 + callingUid + " with uid=" + uid);
4172 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004173 return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004174 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004175 }
4176
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004177 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004178 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004179 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4180 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004181 int callingUid = Binder.getCallingUid();
4182 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004183 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004184 int packageUid = -1;
4185 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004186 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4187 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004188 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
4189 return new Account[0];
4190 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004191 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4192 && !isAccountManagedByCaller(type, callingUid, userId)) {
4193 return new Account[0];
4194 }
4195
4196 return getAccountsAsUser(type, userId,
4197 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004198 }
4199
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004200 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004201 public void getAccountsByFeatures(
4202 IAccountManagerResponse response,
4203 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004204 String[] features,
4205 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004206 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004207 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004208 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4209 Log.v(TAG, "getAccounts: accountType " + type
4210 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004211 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004212 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004213 + ", pid " + Binder.getCallingPid());
4214 }
Fred Quintana382601f2010-03-25 12:25:10 -07004215 if (response == null) throw new IllegalArgumentException("response is null");
4216 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004217 int userId = UserHandle.getCallingUserId();
4218
Svetoslavf3f02ac2015-09-08 14:36:35 -07004219 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4220 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004221 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004222 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004223 // Need to return just the accounts that are from matching signatures.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004224 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);
4225 try {
4226 response.onResult(result);
4227 } catch (RemoteException e) {
4228 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4229 }
4230 return;
4231 }
Fred Quintana33269202009-04-20 16:05:10 -07004232 long identityToken = clearCallingIdentity();
4233 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004234 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004235 if (features == null || features.length == 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004236 Account[] accounts;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004237 synchronized (userAccounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004238 accounts = getAccountsFromCacheLocked(
4239 userAccounts, type, callingUid, opPackageName, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004240 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004241 Bundle result = new Bundle();
4242 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4243 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004244 return;
4245 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004246 new GetAccountsByTypeAndFeatureSession(
4247 userAccounts,
4248 response,
4249 type,
4250 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004251 callingUid,
4252 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004253 } finally {
4254 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004255 }
4256 }
4257
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004258 @Override
4259 public void onAccountAccessed(String token) throws RemoteException {
4260 final int uid = Binder.getCallingUid();
4261 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4262 return;
4263 }
4264 final int userId = UserHandle.getCallingUserId();
4265 final long identity = Binder.clearCallingIdentity();
4266 try {
4267 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4268 if (Objects.equals(account.getAccessId(), token)) {
4269 // An app just accessed the account. At this point it knows about
4270 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004271 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004272 if (!hasAccountAccess(account, null, uid)) {
4273 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4274 uid, true);
4275 }
4276 }
4277 }
4278 } finally {
4279 Binder.restoreCallingIdentity(identity);
4280 }
4281 }
4282
Fred Quintanaa698f422009-04-08 19:14:54 -07004283 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004284 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004285 IAccountManagerResponse mResponse;
4286 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004287 final boolean mExpectActivityLaunch;
4288 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004289 final String mAccountName;
4290 // Indicates if we need to add auth details(like last credential time)
4291 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004292 // If set, we need to update the last authenticated time. This is
4293 // currently
4294 // used on
4295 // successful confirming credentials.
4296 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004297
Fred Quintana33269202009-04-20 16:05:10 -07004298 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004299 private int mNumRequestContinued = 0;
4300 private int mNumErrors = 0;
4301
Fred Quintana60307342009-03-24 22:48:12 -07004302 IAccountAuthenticator mAuthenticator = null;
4303
Fred Quintana8570f742010-02-18 10:32:54 -08004304 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004305 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004306
Amith Yamasani04e0d262012-02-14 11:50:53 -08004307 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004308 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4309 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004310 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4311 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4312 }
4313
4314 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4315 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4316 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004317 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004318 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004319 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004320 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004321 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004322 mResponse = response;
4323 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004324 mExpectActivityLaunch = expectActivityLaunch;
4325 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004326 mAccountName = accountName;
4327 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004328 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004329
Fred Quintanaa698f422009-04-08 19:14:54 -07004330 synchronized (mSessions) {
4331 mSessions.put(toString(), this);
4332 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004333 if (response != null) {
4334 try {
4335 response.asBinder().linkToDeath(this, 0 /* flags */);
4336 } catch (RemoteException e) {
4337 mResponse = null;
4338 binderDied();
4339 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004340 }
Fred Quintana60307342009-03-24 22:48:12 -07004341 }
4342
Fred Quintanaa698f422009-04-08 19:14:54 -07004343 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004344 if (mResponse == null) {
4345 // this session has already been closed
4346 return null;
4347 }
Fred Quintana60307342009-03-24 22:48:12 -07004348 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004349 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004350 return response;
4351 }
4352
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004353 /**
4354 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4355 * security policy.
4356 *
4357 * In particular we want to make sure that the Authenticator doesn't try to trick users
4358 * into launching aribtrary intents on the device via by tricking to click authenticator
4359 * supplied entries in the system Settings app.
4360 */
4361 protected void checkKeyIntent(
4362 int authUid,
4363 Intent intent) throws SecurityException {
4364 long bid = Binder.clearCallingIdentity();
4365 try {
4366 PackageManager pm = mContext.getPackageManager();
4367 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4368 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4369 int targetUid = targetActivityInfo.applicationInfo.uid;
Sandra Kwan0e961a12016-06-30 14:34:01 -07004370 if (!GrantCredentialsPermissionActivity.class.getName().equals(
4371 targetActivityInfo.getClass().getName())
4372 && !CantAddAccountActivity.class
4373 .equals(targetActivityInfo.getClass().getName())
4374 && PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4375 targetUid)) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004376 String pkgName = targetActivityInfo.packageName;
4377 String activityName = targetActivityInfo.name;
4378 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4379 + "does not share a signature with the supplying authenticator (%s).";
4380 throw new SecurityException(
4381 String.format(tmpl, activityName, pkgName, mAccountType));
4382 }
4383 } finally {
4384 Binder.restoreCallingIdentity(bid);
4385 }
4386 }
4387
Fred Quintanaa698f422009-04-08 19:14:54 -07004388 private void close() {
4389 synchronized (mSessions) {
4390 if (mSessions.remove(toString()) == null) {
4391 // the session was already closed, so bail out now
4392 return;
4393 }
4394 }
4395 if (mResponse != null) {
4396 // stop listening for response deaths
4397 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4398
4399 // clear this so that we don't accidentally send any further results
4400 mResponse = null;
4401 }
4402 cancelTimeout();
4403 unbind();
4404 }
4405
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004406 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004407 public void binderDied() {
4408 mResponse = null;
4409 close();
4410 }
4411
4412 protected String toDebugString() {
4413 return toDebugString(SystemClock.elapsedRealtime());
4414 }
4415
4416 protected String toDebugString(long now) {
4417 return "Session: expectLaunch " + mExpectActivityLaunch
4418 + ", connected " + (mAuthenticator != null)
4419 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4420 + "/" + mNumErrors + ")"
4421 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4422 }
4423
Fred Quintana60307342009-03-24 22:48:12 -07004424 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004425 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4426 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4427 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004428 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004429 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004430 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004431 }
4432 }
4433
4434 private void unbind() {
4435 if (mAuthenticator != null) {
4436 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004437 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004438 }
4439 }
4440
Fred Quintana60307342009-03-24 22:48:12 -07004441 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004442 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004443 }
4444
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004445 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004446 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004447 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004448 try {
4449 run();
4450 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004451 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004452 "remote exception");
4453 }
Fred Quintana60307342009-03-24 22:48:12 -07004454 }
4455
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004456 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004457 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004458 mAuthenticator = null;
4459 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004460 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004461 try {
4462 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4463 "disconnected");
4464 } catch (RemoteException e) {
4465 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4466 Log.v(TAG, "Session.onServiceDisconnected: "
4467 + "caught RemoteException while responding", e);
4468 }
4469 }
Fred Quintana60307342009-03-24 22:48:12 -07004470 }
4471 }
4472
Fred Quintanab839afc2009-10-14 15:57:28 -07004473 public abstract void run() throws RemoteException;
4474
Fred Quintana60307342009-03-24 22:48:12 -07004475 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004476 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004477 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004478 try {
4479 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4480 "timeout");
4481 } catch (RemoteException e) {
4482 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4483 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4484 e);
4485 }
4486 }
Fred Quintana60307342009-03-24 22:48:12 -07004487 }
4488 }
4489
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004490 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004491 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004492 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004493 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004494 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004495 if (result != null) {
4496 boolean isSuccessfulConfirmCreds = result.getBoolean(
4497 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004498 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004499 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4500 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004501 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004502 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4503 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004504 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004505 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004506 if (needUpdate || mAuthDetailsRequired) {
4507 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4508 if (needUpdate && accountPresent) {
4509 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4510 }
4511 if (mAuthDetailsRequired) {
4512 long lastAuthenticatedTime = -1;
4513 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004514 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004515 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004516 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004517 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004518 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004519 lastAuthenticatedTime);
4520 }
4521 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004522 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004523 if (result != null
4524 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004525 checkKeyIntent(
4526 Binder.getCallingUid(),
4527 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004528 }
4529 if (result != null
4530 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004531 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4532 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004533 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4534 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004535 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4536 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004537 }
Fred Quintana60307342009-03-24 22:48:12 -07004538 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004539 IAccountManagerResponse response;
4540 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004541 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004542 response = mResponse;
4543 } else {
4544 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004545 }
Fred Quintana60307342009-03-24 22:48:12 -07004546 if (response != null) {
4547 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004548 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004549 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4550 Log.v(TAG, getClass().getSimpleName()
4551 + " calling onError() on response " + response);
4552 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004553 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004554 "null bundle returned");
4555 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004556 if (mStripAuthTokenFromResult) {
4557 result.remove(AccountManager.KEY_AUTHTOKEN);
4558 }
Fred Quintana56285a62010-12-02 14:20:51 -08004559 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4560 Log.v(TAG, getClass().getSimpleName()
4561 + " calling onResult() on response " + response);
4562 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004563 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4564 (intent == null)) {
4565 // All AccountManager error codes are greater than 0
4566 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4567 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4568 } else {
4569 response.onResult(result);
4570 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004571 }
Fred Quintana60307342009-03-24 22:48:12 -07004572 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004573 // if the caller is dead then there is no one to care about remote exceptions
4574 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4575 Log.v(TAG, "failure while notifying response", e);
4576 }
Fred Quintana60307342009-03-24 22:48:12 -07004577 }
4578 }
4579 }
Fred Quintana60307342009-03-24 22:48:12 -07004580
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004581 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004582 public void onRequestContinued() {
4583 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004584 }
4585
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004586 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004587 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004588 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004589 IAccountManagerResponse response = getResponseAndClose();
4590 if (response != null) {
4591 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004592 Log.v(TAG, getClass().getSimpleName()
4593 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004594 }
4595 try {
4596 response.onError(errorCode, errorMessage);
4597 } catch (RemoteException e) {
4598 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4599 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4600 }
4601 }
4602 } else {
4603 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4604 Log.v(TAG, "Session.onError: already closed");
4605 }
Fred Quintana60307342009-03-24 22:48:12 -07004606 }
4607 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004608
4609 /**
4610 * find the component name for the authenticator and initiate a bind
4611 * if no authenticator or the bind fails then return false, otherwise return true
4612 */
4613 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004614 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4615 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4616 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004617 if (authenticatorInfo == null) {
4618 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4619 Log.v(TAG, "there is no authenticator for " + authenticatorType
4620 + ", bailing out");
4621 }
4622 return false;
4623 }
4624
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004625 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004626 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004627 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4628 + " which isn't encryption aware");
4629 return false;
4630 }
4631
Fred Quintanab839afc2009-10-14 15:57:28 -07004632 Intent intent = new Intent();
4633 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4634 intent.setComponent(authenticatorInfo.componentName);
4635 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4636 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4637 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004638 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004639 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004640 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4641 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4642 }
4643 return false;
4644 }
4645
Fred Quintanab839afc2009-10-14 15:57:28 -07004646 return true;
4647 }
Fred Quintana60307342009-03-24 22:48:12 -07004648 }
4649
Svet Ganov5d09c992016-09-07 09:57:41 -07004650 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004651 MessageHandler(Looper looper) {
4652 super(looper);
4653 }
Costin Manolache3348f142009-09-29 18:58:36 -07004654
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004655 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004656 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004657 switch (msg.what) {
4658 case MESSAGE_TIMED_OUT:
4659 Session session = (Session)msg.obj;
4660 session.onTimedOut();
4661 break;
4662
Amith Yamasani5be347b2013-03-31 17:44:31 -07004663 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004664 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004665 break;
4666
Fred Quintana60307342009-03-24 22:48:12 -07004667 default:
4668 throw new IllegalStateException("unhandled message: " + msg.what);
4669 }
4670 }
4671 }
4672
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004673 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004674 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004675 }
4676
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004677 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004678 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004679 }
4680
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004681 /*
4682 * This function receives an opened writable database.
4683 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004684 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004685 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004686 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004687 }
4688
4689 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004690 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004691 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004692 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004693 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004694
4695 class LogRecordTask implements Runnable {
4696 private final String action;
4697 private final String tableName;
4698 private final long accountId;
4699 private final UserAccounts userAccount;
4700 private final int callingUid;
4701 private final long userDebugDbInsertionPoint;
4702
4703 LogRecordTask(final String action,
4704 final String tableName,
4705 final long accountId,
4706 final UserAccounts userAccount,
4707 final int callingUid,
4708 final long userDebugDbInsertionPoint) {
4709 this.action = action;
4710 this.tableName = tableName;
4711 this.accountId = accountId;
4712 this.userAccount = userAccount;
4713 this.callingUid = callingUid;
4714 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4715 }
4716
4717 public void run() {
4718 SQLiteStatement logStatement = userAccount.statementForLogging;
4719 logStatement.bindLong(1, accountId);
4720 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004721 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004722 logStatement.bindLong(4, callingUid);
4723 logStatement.bindString(5, tableName);
4724 logStatement.bindLong(6, userDebugDbInsertionPoint);
4725 logStatement.execute();
4726 logStatement.clearBindings();
4727 }
4728 }
4729
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004730 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4731 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004732 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004733 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004734 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004735 }
4736
4737 /*
4738 * This should only be called once to compile the sql statement for logging
4739 * and to find the insertion point.
4740 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004741 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4742 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4743 .calculateDebugTableInsertionPoint();
4744 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004745 }
4746
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004747 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004748 return asBinder();
4749 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004750
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004751 /**
4752 * Searches array of arguments for the specified string
4753 * @param args array of argument strings
4754 * @param value value to search for
4755 * @return true if the value is contained in the array
4756 */
4757 private static boolean scanArgs(String[] args, String value) {
4758 if (args != null) {
4759 for (String arg : args) {
4760 if (value.equals(arg)) {
4761 return true;
4762 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004763 }
4764 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004765 return false;
4766 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004767
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004768 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004769 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Kenny Root3abd75b2011-09-29 11:00:41 -07004770 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4771 != PackageManager.PERMISSION_GRANTED) {
4772 fout.println("Permission Denial: can't dump AccountsManager from from pid="
4773 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
4774 + " without permission " + android.Manifest.permission.DUMP);
4775 return;
4776 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004777 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004778 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004779
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004780 final List<UserInfo> users = getUserManager().getUsers();
4781 for (UserInfo user : users) {
4782 ipw.println("User " + user + ":");
4783 ipw.increaseIndent();
4784 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4785 ipw.println();
4786 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004787 }
4788 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004789
Amith Yamasani04e0d262012-02-14 11:50:53 -08004790 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4791 String[] args, boolean isCheckinRequest) {
4792 synchronized (userAccounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004793 if (isCheckinRequest) {
4794 // This is a checkin request. *Only* upload the account types and the count of each.
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004795 userAccounts.accountsDb.dumpDeAccountsTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004796 } else {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004797 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004798 Process.SYSTEM_UID, null /* packageName */, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004799 fout.println("Accounts: " + accounts.length);
4800 for (Account account : accounts) {
4801 fout.println(" " + account);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004802 }
Fred Quintana307da1a2010-01-21 14:24:20 -08004803
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004804 // Add debug information.
4805 fout.println();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004806 userAccounts.accountsDb.dumpDebugTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004807 fout.println();
4808 synchronized (mSessions) {
4809 final long now = SystemClock.elapsedRealtime();
4810 fout.println("Active Sessions: " + mSessions.size());
4811 for (Session session : mSessions.values()) {
4812 fout.println(" " + session.toDebugString(now));
4813 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004814 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004815
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004816 fout.println();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004817 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004818 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004819 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004820 }
4821
Amith Yamasani04e0d262012-02-14 11:50:53 -08004822 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004823 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004824 long identityToken = clearCallingIdentity();
4825 try {
4826 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4827 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4828 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004829
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004830 if (intent.getComponent() != null &&
4831 GrantCredentialsPermissionActivity.class.getName().equals(
4832 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004833 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004834 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004835 Context contextForUser = getContextForUser(new UserHandle(userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004836 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07004837 intent.addCategory(String.valueOf(notificationId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004838
Fred Quintana33f889a2009-09-14 17:31:26 -07004839 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004840 contextForUser.getText(R.string.notification_title).toString();
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004841 Notification n = new Notification.Builder(contextForUser)
4842 .setWhen(0)
4843 .setSmallIcon(android.R.drawable.stat_sys_warning)
4844 .setColor(contextForUser.getColor(
4845 com.android.internal.R.color.system_notification_accent_color))
4846 .setContentTitle(String.format(notificationTitleFormat, account.name))
4847 .setContentText(message)
4848 .setContentIntent(PendingIntent.getActivityAsUser(
4849 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004850 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004851 .build();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004852 installNotification(notificationId, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004853 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004854 } finally {
4855 restoreCallingIdentity(identityToken);
4856 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004857 }
4858
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004859 private void installNotification(int notificationId, final Notification notification,
4860 String packageName, int userId) {
4861 final long token = clearCallingIdentity();
4862 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004863 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004864 try {
4865 notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
4866 notificationId, notification, new int[1], userId);
4867 } catch (RemoteException e) {
4868 /* ignore - local call */
4869 }
4870 } finally {
4871 Binder.restoreCallingIdentity(token);
4872 }
Fred Quintana56285a62010-12-02 14:20:51 -08004873 }
4874
Fyodor Kupolovda993802016-09-21 14:47:10 -07004875 private void cancelNotification(int id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004876 cancelNotification(id, mContext.getPackageName(), user);
4877 }
4878
Fyodor Kupolovda993802016-09-21 14:47:10 -07004879 private void cancelNotification(int id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004880 long identityToken = clearCallingIdentity();
4881 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004882 INotificationManager service = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004883 service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
4884 } catch (RemoteException e) {
4885 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004886 } finally {
4887 restoreCallingIdentity(identityToken);
4888 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004889 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004890
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004891 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
4892 final long identity = Binder.clearCallingIdentity();
4893 try {
4894 IPackageManager pm = ActivityThread.getPackageManager();
4895 for (String perm : permissions) {
4896 if (pm.checkPermission(perm, packageName, userId)
4897 == PackageManager.PERMISSION_GRANTED) {
4898 return true;
4899 }
4900 }
4901 } catch (RemoteException e) {
4902 /* ignore - local call */
4903 } finally {
4904 Binder.restoreCallingIdentity(identity);
4905 }
4906 return false;
4907 }
4908
Ian Pedowitz358e51f2016-03-15 17:08:27 +00004909 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
4910 for (String perm : permissions) {
4911 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
4912 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4913 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
4914 }
4915 final int opCode = AppOpsManager.permissionToOpCode(perm);
4916 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
4917 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
4918 return true;
4919 }
4920 }
4921 }
4922 return false;
4923 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004924
Amith Yamasani67df64b2012-12-14 12:09:36 -08004925 private int handleIncomingUser(int userId) {
4926 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004927 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08004928 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
4929 } catch (RemoteException re) {
4930 // Shouldn't happen, local.
4931 }
4932 return userId;
4933 }
4934
Christopher Tateccbf84f2013-05-08 15:25:41 -07004935 private boolean isPrivileged(int callingUid) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004936 final int callingUserId = UserHandle.getUserId(callingUid);
4937
4938 final PackageManager userPackageManager;
4939 try {
4940 userPackageManager = mContext.createPackageContextAsUser(
4941 "android", 0, new UserHandle(callingUserId)).getPackageManager();
4942 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004943 Log.d(TAG, "Package not found " + e.getMessage());
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004944 return false;
4945 }
4946
4947 String[] packages = userPackageManager.getPackagesForUid(callingUid);
Fred Quintana7be59642009-08-24 18:29:25 -07004948 for (String name : packages) {
4949 try {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004950 PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08004951 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08004952 && (packageInfo.applicationInfo.privateFlags
4953 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07004954 return true;
4955 }
4956 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004957 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07004958 return false;
4959 }
4960 }
4961 return false;
4962 }
4963
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004964 private boolean permissionIsGranted(
4965 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004966 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
4967 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4968 Log.v(TAG, "Access to " + account + " granted calling uid is system");
4969 }
4970 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004971 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004972
4973 if (isPrivileged(callerUid)) {
4974 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4975 Log.v(TAG, "Access to " + account + " granted calling uid "
4976 + callerUid + " privileged");
4977 }
4978 return true;
4979 }
4980 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
4981 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4982 Log.v(TAG, "Access to " + account + " granted calling uid "
4983 + callerUid + " manages the account");
4984 }
4985 return true;
4986 }
4987 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
4988 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4989 Log.v(TAG, "Access to " + account + " granted calling uid "
4990 + callerUid + " user granted access");
4991 }
4992 return true;
4993 }
4994
4995 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4996 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
4997 }
4998
4999 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005000 }
5001
Svetoslavf3f02ac2015-09-08 14:36:35 -07005002 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5003 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005004 if (accountType == null) {
5005 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005006 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005007 return getTypesVisibleToCaller(callingUid, userId,
5008 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005009 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005010 }
5011
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005012 // Method checks visibility for applications targeing API level below {@link
5013 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005014 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005015 private boolean checkGetAccountsPermission(String packageName, int userId) {
5016 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5017 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5018 }
5019
5020 private boolean checkReadContactsPermission(String packageName, int userId) {
5021 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5022 }
5023
5024 /**
5025 * Method checks package uid and signature with Authenticator which manages accountType.
5026 *
5027 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5028 * SIGNATURE_CHECK_MISMATCH otherwise.
5029 */
5030 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5031 if (accountType == null) {
5032 return SIGNATURE_CHECK_MISMATCH;
5033 }
5034
5035 long identityToken = Binder.clearCallingIdentity();
5036 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5037 try {
5038 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5039 } finally {
5040 Binder.restoreCallingIdentity(identityToken);
5041 }
5042 // Check for signature match with Authenticator.
5043 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5044 : serviceInfos) {
5045 if (accountType.equals(serviceInfo.type.type)) {
5046 if (serviceInfo.uid == callingUid) {
5047 return SIGNATURE_CHECK_UID_MATCH;
5048 }
5049 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5050 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5051 return SIGNATURE_CHECK_MATCH;
5052 }
5053 }
5054 }
5055 return SIGNATURE_CHECK_MISMATCH;
5056 }
5057
5058 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005059 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5060 if (accountType == null) {
5061 return false;
5062 } else {
5063 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5064 }
5065 }
5066
Svetoslavf3f02ac2015-09-08 14:36:35 -07005067 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5068 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005069 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005070 }
5071
5072 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005073 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005074 }
5075
5076 private List<String> getTypesForCaller(
5077 int callingUid, int userId, boolean isOtherwisePermitted) {
5078 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005079 long identityToken = Binder.clearCallingIdentity();
5080 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5081 try {
5082 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5083 } finally {
5084 Binder.restoreCallingIdentity(identityToken);
5085 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005086 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005087 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005088 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5089 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005090 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005091 }
5092 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005093 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005094 }
5095
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005096 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5097 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5098 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5099 if (account.name.equals(accountName)) {
5100 return true;
5101 }
5102 }
5103 }
5104 return false;
5105 }
5106
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005107 private static void checkManageUsersPermission(String message) {
5108 if (ActivityManager.checkComponentPermission(
5109 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5110 != PackageManager.PERMISSION_GRANTED) {
5111 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5112 }
5113 }
5114
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005115 private static void checkManageOrCreateUsersPermission(String message) {
5116 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5117 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5118 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5119 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5120 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5121 + message);
5122 }
5123 }
5124
Amith Yamasani04e0d262012-02-14 11:50:53 -08005125 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5126 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005127 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005128 return true;
5129 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005130 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005131 synchronized (accounts.cacheLock) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005132 long grantsCount;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005133 if (authTokenType != null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005134 grantsCount = accounts.accountsDb.findMatchingGrantsCount(callerUid, authTokenType,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005135 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005136 } else {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005137 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005138 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005139 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005140 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005141
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005142 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5143 // TODO: Skip this check when running automated tests. Replace this
5144 // with a more general solution.
5145 Log.d(TAG, "no credentials permission for usage of " + account + ", "
Amith Yamasani04e0d262012-02-14 11:50:53 -08005146 + authTokenType + " by uid " + callerUid
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005147 + " but ignoring since device is in test harness.");
5148 return true;
5149 }
5150 return permissionGranted;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005151 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005152 }
5153
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005154 private boolean isSystemUid(int callingUid) {
5155 String[] packages = null;
5156 long ident = Binder.clearCallingIdentity();
5157 try {
5158 packages = mPackageManager.getPackagesForUid(callingUid);
5159 } finally {
5160 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005161 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005162 if (packages != null) {
5163 for (String name : packages) {
5164 try {
5165 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5166 if (packageInfo != null
5167 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5168 != 0) {
5169 return true;
5170 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005171 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005172 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5173 }
5174 }
5175 } else {
5176 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005177 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005178 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005179 }
5180
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005181 /** Succeeds if any of the specified permissions are granted. */
5182 private void checkReadAccountsPermitted(
5183 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005184 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005185 int userId,
5186 String opPackageName) {
5187 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005188 String msg = String.format(
5189 "caller uid %s cannot access %s accounts",
5190 callingUid,
5191 accountType);
5192 Log.w(TAG, " " + msg);
5193 throw new SecurityException(msg);
5194 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005195 }
5196
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005197 private boolean canUserModifyAccounts(int userId, int callingUid) {
5198 // the managing app can always modify accounts
5199 if (isProfileOwner(callingUid)) {
5200 return true;
5201 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005202 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5203 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5204 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005205 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005206 return true;
5207 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005208
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005209 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5210 // the managing app can always modify accounts
5211 if (isProfileOwner(callingUid)) {
5212 return true;
5213 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005214 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5215 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005216 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005217 if (typesArray == null) {
5218 return true;
5219 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005220 for (String forbiddenType : typesArray) {
5221 if (forbiddenType.equals(accountType)) {
5222 return false;
5223 }
5224 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005225 return true;
5226 }
5227
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005228 private boolean isProfileOwner(int uid) {
5229 final DevicePolicyManagerInternal dpmi =
5230 LocalServices.getService(DevicePolicyManagerInternal.class);
5231 return (dpmi != null)
5232 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5233 }
5234
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005235 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005236 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5237 throws RemoteException {
5238 final int callingUid = getCallingUid();
5239
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005240 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005241 throw new SecurityException();
5242 }
5243
5244 if (value) {
5245 grantAppPermission(account, authTokenType, uid);
5246 } else {
5247 revokeAppPermission(account, authTokenType, uid);
5248 }
5249 }
5250
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005251 /**
5252 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5253 * <p>
5254 * Although this is public it can only be accessed via the AccountManagerService object
5255 * which is in the system. This means we don't need to protect it with permissions.
5256 * @hide
5257 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005258 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005259 if (account == null || authTokenType == null) {
5260 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005261 return;
5262 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005263 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005264 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005265 long accountId = accounts.accountsDb.findDeAccountId(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005266 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005267 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005268 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005269 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005270 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005271
5272 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005273 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005274
5275 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5276 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5277 : mAppPermissionChangeListeners) {
5278 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5279 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005280 }
5281
5282 /**
5283 * Don't allow callers with the given uid permission to get credentials for
5284 * account/authTokenType.
5285 * <p>
5286 * Although this is public it can only be accessed via the AccountManagerService object
5287 * which is in the system. This means we don't need to protect it with permissions.
5288 * @hide
5289 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005290 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005291 if (account == null || authTokenType == null) {
5292 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005293 return;
5294 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005295 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005296 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005297 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005298 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005299 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005300 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005301 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5302 accountId, authTokenType, uid);
5303 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005304 }
5305 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005306 accounts.accountsDb.endTransaction();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005307 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005308
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005309 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
5310 new UserHandle(accounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005311 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005312
5313 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5314 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5315 : mAppPermissionChangeListeners) {
5316 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5317 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005318 }
Fred Quintana56285a62010-12-02 14:20:51 -08005319
Amith Yamasani04e0d262012-02-14 11:50:53 -08005320 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5321 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005322 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005323 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005324 for (Account curAccount : oldAccountsForType) {
5325 if (!curAccount.equals(account)) {
5326 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005327 }
5328 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005329 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005330 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005331 } else {
5332 Account[] newAccountsForType = new Account[newAccountsList.size()];
5333 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005334 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005335 }
Fred Quintana56285a62010-12-02 14:20:51 -08005336 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005337 accounts.userDataCache.remove(account);
5338 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005339 accounts.previousNameCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005340 }
5341
5342 /**
5343 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005344 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5345 * processes and if you will return this account to apps you should return the result.
5346 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005347 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005348 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005349 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005350 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5351 Account[] newAccountsForType = new Account[oldLength + 1];
5352 if (accountsForType != null) {
5353 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005354 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005355 String token = account.getAccessId() != null ? account.getAccessId()
5356 : UUID.randomUUID().toString();
5357 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005358 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005359 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005360 }
5361
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005362 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
5363 String callingPackage, boolean includeManagedNotVisible) {
5364 // filter based on visibility.
5365 Map<Account, Integer> firstPass = new HashMap<>();
5366 for (Account account : unfiltered) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005367 int visibility = resolveAccountVisibility(account, callingPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005368 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5369 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5370 || (includeManagedNotVisible
5371 && (visibility
5372 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5373 firstPass.put(account, visibility);
5374 }
5375 }
5376 Map<Account, Integer> secondPass =
5377 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5378
5379 Account[] filtered = new Account[secondPass.size()];
5380 filtered = secondPass.keySet().toArray(filtered);
5381 return filtered;
5382 }
5383
5384 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
5385 Map<Account, Integer> unfiltered, int callingUid, String callingPackage) {
5386 // first part is to filter shared accounts.
5387 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005388 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005389 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005390 return unfiltered;
5391 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005392 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005393 if (user != null && user.isRestricted()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005394 String[] packages =
5395 mPackageManager.getPackagesForUid(callingUid);
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005396 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005397 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005398 // This might be a temporary way to specify a visible list
5399 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005400 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5401 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005402 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005403 return unfiltered;
5404 }
5405 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005406 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005407 if (ArrayUtils.isEmpty(sharedAccounts)) {
5408 return unfiltered;
5409 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005410 String requiredAccountType = "";
5411 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005412 // If there's an explicit callingPackage specified, check if that package
5413 // opted in to see restricted accounts.
5414 if (callingPackage != null) {
5415 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005416 if (pi != null && pi.restrictedAccountType != null) {
5417 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005418 }
5419 } else {
5420 // Otherwise check if the callingUid has a package that has opted in
5421 for (String packageName : packages) {
5422 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5423 if (pi != null && pi.restrictedAccountType != null) {
5424 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005425 break;
5426 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005427 }
5428 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005429 } catch (NameNotFoundException e) {
5430 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005431 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005432 Map<Account, Integer> filtered = new HashMap<>();
5433 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5434 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005435 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005436 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005437 } else {
5438 boolean found = false;
5439 for (Account shared : sharedAccounts) {
5440 if (shared.equals(account)) {
5441 found = true;
5442 break;
5443 }
5444 }
5445 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005446 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005447 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005448 }
5449 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005450 return filtered;
5451 } else {
5452 return unfiltered;
5453 }
5454 }
5455
Amith Yamasani27db4682013-03-30 17:07:47 -07005456 /*
5457 * packageName can be null. If not null, it should be used to filter out restricted accounts
5458 * that the package is not allowed to access.
5459 */
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005460 protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005461 int callingUid, String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005462 if (callingPackage == null) {
5463 callingPackage = getPackageNameForUid(callingUid);
5464 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005465 if (accountType != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005466 final Account[] accounts = userAccounts.accountCache.get(accountType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005467 if (accounts == null) {
5468 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005469 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005470 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5471 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005472 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005473 } else {
5474 int totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005475 for (Account[] accounts : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005476 totalLength += accounts.length;
5477 }
5478 if (totalLength == 0) {
5479 return EMPTY_ACCOUNT_ARRAY;
5480 }
5481 Account[] accounts = new Account[totalLength];
5482 totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005483 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005484 System.arraycopy(accountsOfType, 0, accounts, totalLength,
5485 accountsOfType.length);
5486 totalLength += accountsOfType.length;
5487 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005488 return filterAccounts(userAccounts, accounts, callingUid, callingPackage,
5489 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005490 }
5491 }
5492
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005493 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005494 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005495 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005496 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005497 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005498 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005499 }
5500 if (value == null) {
5501 userDataForAccount.remove(key);
5502 } else {
5503 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005504 }
5505 }
5506
Carlos Valdivia91979be2015-05-22 14:11:35 -07005507 protected String readCachedTokenInternal(
5508 UserAccounts accounts,
5509 Account account,
5510 String tokenType,
5511 String callingPackage,
5512 byte[] pkgSigDigest) {
5513 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005514 return accounts.accountTokenCaches.get(
5515 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07005516 }
5517 }
5518
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005519 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005520 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005521 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005522 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005523 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005524 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005525 }
5526 if (value == null) {
5527 authTokensForAccount.remove(key);
5528 } else {
5529 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005530 }
5531 }
5532
Amith Yamasani04e0d262012-02-14 11:50:53 -08005533 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5534 String authTokenType) {
5535 synchronized (accounts.cacheLock) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005536 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005537 if (authTokensForAccount == null) {
5538 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005539 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005540 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005541 }
5542 return authTokensForAccount.get(authTokenType);
5543 }
5544 }
5545
Simranjit Kohli858511c2016-03-10 18:36:11 +00005546 protected String readUserDataInternalLocked(
5547 UserAccounts accounts, Account account, String key) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005548 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005549 if (userDataForAccount == null) {
5550 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005551 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005552 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005553 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005554 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005555 }
5556
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005557 private Context getContextForUser(UserHandle user) {
5558 try {
5559 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5560 } catch (NameNotFoundException e) {
5561 // Default to mContext, not finding the package system is running as is unlikely.
5562 return mContext;
5563 }
5564 }
Sandra Kwan78812282015-11-04 11:19:47 -08005565
5566 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5567 try {
5568 response.onResult(result);
5569 } catch (RemoteException e) {
5570 // if the caller is dead then there is no one to care about remote
5571 // exceptions
5572 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5573 Log.v(TAG, "failure while notifying response", e);
5574 }
5575 }
5576 }
5577
5578 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5579 String errorMessage) {
5580 try {
5581 response.onError(errorCode, errorMessage);
5582 } catch (RemoteException e) {
5583 // if the caller is dead then there is no one to care about remote
5584 // exceptions
5585 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5586 Log.v(TAG, "failure while notifying response", e);
5587 }
5588 }
5589 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005590
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005591 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005592 private final Object mLock = new Object();
5593
5594 @GuardedBy("mLock")
5595 private AccountManagerBackupHelper mBackupHelper;
5596
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005597 @Override
5598 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5599 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5600 if (account == null) {
5601 Slog.w(TAG, "account cannot be null");
5602 return;
5603 }
5604 if (packageName == null) {
5605 Slog.w(TAG, "packageName cannot be null");
5606 return;
5607 }
5608 if (userId < UserHandle.USER_SYSTEM) {
5609 Slog.w(TAG, "user id must be concrete");
5610 return;
5611 }
5612 if (callback == null) {
5613 Slog.w(TAG, "callback cannot be null");
5614 return;
5615 }
5616
Svet Ganovf6d424f12016-09-20 20:18:53 -07005617 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5618 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005619 Bundle result = new Bundle();
5620 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5621 callback.sendResult(result);
5622 return;
5623 }
5624
5625 final int uid;
5626 try {
5627 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5628 } catch (NameNotFoundException e) {
5629 Slog.e(TAG, "Unknown package " + packageName);
5630 return;
5631 }
5632
5633 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005634 final UserAccounts userAccounts;
5635 synchronized (mUsers) {
5636 userAccounts = mUsers.get(userId);
5637 }
5638 doNotification(userAccounts, account, null, intent, packageName, userId);
5639 }
5640
5641 @Override
5642 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5643 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5644 mAppPermissionChangeListeners.add(listener);
5645 }
5646
5647 @Override
5648 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5649 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005650 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005651
5652 @Override
5653 public byte[] backupAccountAccessPermissions(int userId) {
5654 synchronized (mLock) {
5655 if (mBackupHelper == null) {
5656 mBackupHelper = new AccountManagerBackupHelper(
5657 AccountManagerService.this, this);
5658 }
5659 return mBackupHelper.backupAccountAccessPermissions(userId);
5660 }
5661 }
5662
5663 @Override
5664 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5665 synchronized (mLock) {
5666 if (mBackupHelper == null) {
5667 mBackupHelper = new AccountManagerBackupHelper(
5668 AccountManagerService.this, this);
5669 }
5670 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5671 }
5672 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005673 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005674
5675 @VisibleForTesting
5676 static class Injector {
5677 private final Context mContext;
5678
5679 public Injector(Context context) {
5680 mContext = context;
5681 }
5682
5683 Looper getMessageHandlerLooper() {
5684 ServiceThread serviceThread = new ServiceThread(TAG,
5685 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5686 serviceThread.start();
5687 return serviceThread.getLooper();
5688 }
5689
5690 Context getContext() {
5691 return mContext;
5692 }
5693
5694 void addLocalService(AccountManagerInternal service) {
5695 LocalServices.addService(AccountManagerInternal.class, service);
5696 }
5697
5698 String getDeDatabaseName(int userId) {
5699 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5700 AccountsDb.DE_DATABASE_NAME);
5701 return databaseFile.getPath();
5702 }
5703
5704 String getCeDatabaseName(int userId) {
5705 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5706 AccountsDb.CE_DATABASE_NAME);
5707 return databaseFile.getPath();
5708 }
5709
5710 String getPreNDatabaseName(int userId) {
5711 File systemDir = Environment.getDataSystemDirectory();
5712 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5713 PRE_N_DATABASE_NAME);
5714 if (userId == 0) {
5715 // Migrate old file, if it exists, to the new location.
5716 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005717 // accidentally created in the old location,
5718 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005719 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5720 if (oldFile.exists() && !databaseFile.exists()) {
5721 // Check for use directory; create if it doesn't exist, else renameTo will fail
5722 File userDir = Environment.getUserSystemDirectory(userId);
5723 if (!userDir.exists()) {
5724 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005725 throw new IllegalStateException(
5726 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005727 }
5728 }
5729 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005730 throw new IllegalStateException(
5731 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005732 }
5733 }
5734 }
5735 return databaseFile.getPath();
5736 }
5737
5738 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5739 return new AccountAuthenticatorCache(mContext);
5740 }
5741
5742 INotificationManager getNotificationManager() {
5743 return NotificationManager.getService();
5744 }
5745 }
Fred Quintana60307342009-03-24 22:48:12 -07005746}