blob: dade0ed011fc37d0d8c180c312cfde3bcb3c1afc [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;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050095import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani67df64b2012-12-14 12:09:36 -080096import com.android.internal.util.ArrayUtils;
Amith Yamasani04e0d262012-02-14 11:50:53 -080097import com.android.internal.util.IndentingPrintWriter;
Fyodor Kupolov35f68082016-04-06 12:14:17 -070098import com.android.internal.util.Preconditions;
Benjamin Franzb6c0ce42015-11-05 10:06:51 +000099import com.android.server.LocalServices;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700100import com.android.server.ServiceThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600101import com.android.server.SystemService;
102
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700103import com.google.android.collect.Lists;
104import com.google.android.collect.Sets;
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700105
Oscar Montemayora8529f62009-11-18 10:14:20 -0800106import java.io.File;
Fred Quintanaa698f422009-04-08 19:14:54 -0700107import java.io.FileDescriptor;
108import java.io.PrintWriter;
Sandra Kwan78812282015-11-04 11:19:47 -0800109import java.security.GeneralSecurityException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700110import java.security.MessageDigest;
111import java.security.NoSuchAlgorithmException;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700112import java.text.SimpleDateFormat;
Fred Quintanaa698f422009-04-08 19:14:54 -0700113import java.util.ArrayList;
Fred Quintana56285a62010-12-02 14:20:51 -0800114import java.util.Arrays;
Fred Quintanaa698f422009-04-08 19:14:54 -0700115import java.util.Collection;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800116import java.util.Collections;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700117import java.util.Date;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700118import java.util.HashMap;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700119import java.util.HashSet;
Fred Quintana56285a62010-12-02 14:20:51 -0800120import java.util.LinkedHashMap;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800121import java.util.LinkedHashSet;
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700122import java.util.List;
Andy McFadden2f362292012-01-20 14:43:38 -0800123import java.util.Map;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800124import java.util.Map.Entry;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700125import java.util.Objects;
Svet Ganovc1c0d1c2016-09-23 19:15:47 -0700126import java.util.UUID;
Svet Ganovf6d424f12016-09-20 20:18:53 -0700127import java.util.concurrent.CopyOnWriteArrayList;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700128import java.util.concurrent.atomic.AtomicInteger;
129import java.util.concurrent.atomic.AtomicReference;
Fred Quintana60307342009-03-24 22:48:12 -0700130
Fred Quintana60307342009-03-24 22:48:12 -0700131/**
132 * A system service that provides account, password, and authtoken management for all
133 * accounts on the device. Some of these calls are implemented with the help of the corresponding
134 * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
135 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
Brian Carlstrom46703b02011-04-06 15:41:29 -0700136 * AccountManager accountManager = AccountManager.get(context);
Fred Quintana33269202009-04-20 16:05:10 -0700137 * @hide
Fred Quintana60307342009-03-24 22:48:12 -0700138 */
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700139public class AccountManagerService
140 extends IAccountManager.Stub
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800141 implements RegisteredServicesCacheListener<AuthenticatorDescription> {
Fred Quintana60307342009-03-24 22:48:12 -0700142 private static final String TAG = "AccountManagerService";
143
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600144 public static class Lifecycle extends SystemService {
145 private AccountManagerService mService;
146
147 public Lifecycle(Context context) {
148 super(context);
149 }
150
151 @Override
152 public void onStart() {
Fyodor Kupolovda993802016-09-21 14:47:10 -0700153 mService = new AccountManagerService(new Injector(getContext()));
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600154 publishBinderService(Context.ACCOUNT_SERVICE, mService);
155 }
156
157 @Override
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600158 public void onUnlockUser(int userHandle) {
159 mService.onUnlockUser(userHandle);
160 }
161 }
162
Svet Ganov5d09c992016-09-07 09:57:41 -0700163 final Context mContext;
Fred Quintana60307342009-03-24 22:48:12 -0700164
Fred Quintana56285a62010-12-02 14:20:51 -0800165 private final PackageManager mPackageManager;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700166 private final AppOpsManager mAppOpsManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700167 private UserManager mUserManager;
Fyodor Kupolovda993802016-09-21 14:47:10 -0700168 private final Injector mInjector;
Fred Quintana56285a62010-12-02 14:20:51 -0800169
Svet Ganov5d09c992016-09-07 09:57:41 -0700170 final MessageHandler mHandler;
Tejas Khorana7b88f0e2016-06-13 13:06:35 -0700171
Fred Quintana60307342009-03-24 22:48:12 -0700172 // Messages that can be sent on mHandler
173 private static final int MESSAGE_TIMED_OUT = 3;
Amith Yamasani5be347b2013-03-31 17:44:31 -0700174 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
Fred Quintana60307342009-03-24 22:48:12 -0700175
Fred Quintana56285a62010-12-02 14:20:51 -0800176 private final IAccountAuthenticatorCache mAuthenticatorCache;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700177 private static final String PRE_N_DATABASE_NAME = "accounts.db";
Fred Quintana7be59642009-08-24 18:29:25 -0700178 private static final Intent ACCOUNTS_CHANGED_INTENT;
Sandra Kwan390c9d22016-01-12 14:13:37 -0800179
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800180 private static final int SIGNATURE_CHECK_MISMATCH = 0;
181 private static final int SIGNATURE_CHECK_MATCH = 1;
182 private static final int SIGNATURE_CHECK_UID_MATCH = 2;
183
Carlos Valdivia91979be2015-05-22 14:11:35 -0700184 static {
185 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
Christopher Tatebded68f2017-02-21 11:41:55 -0800186 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
187 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700188 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700189
190 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700191 private final AtomicInteger mNotificationIds = new AtomicInteger(1);
192
Amith Yamasani04e0d262012-02-14 11:50:53 -0800193 static class UserAccounts {
194 private final int userId;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700195 final AccountsDb accountsDb;
Amith Yamasani04e0d262012-02-14 11:50:53 -0800196 private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
197 credentialsPermissionNotificationIds =
198 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
199 private final HashMap<Account, Integer> signinRequiredNotificationIds =
200 new HashMap<Account, Integer>();
Svet Ganov5d09c992016-09-07 09:57:41 -0700201 final Object cacheLock = new Object();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800202 /** protected by the {@link #cacheLock} */
Svet Ganov5d09c992016-09-07 09:57:41 -0700203 final HashMap<String, Account[]> accountCache =
Svet Ganovf6d424f12016-09-20 20:18:53 -0700204 new LinkedHashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800205 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700206 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800207 /** protected by the {@link #cacheLock} */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700208 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700209 /** protected by the {@link #cacheLock} */
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700210 private final TokenCache accountTokenCaches = new TokenCache();
Carlos Valdivia91979be2015-05-22 14:11:35 -0700211
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800212 /** protected by the {@link #cacheLock} */
213 // TODO use callback to set up the map.
214 private final Map<String, LinkedHashSet<String>> mApplicationAccountRequestMappings =
215 new HashMap<>();
216
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700217 /**
218 * protected by the {@link #cacheLock}
219 *
220 * Caches the previous names associated with an account. Previous names
221 * should be cached because we expect that when an Account is renamed,
222 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and
223 * want to know if the accounts they care about have been renamed.
224 *
225 * The previous names are wrapped in an {@link AtomicReference} so that
226 * we can distinguish between those accounts with no previous names and
227 * those whose previous names haven't been cached (yet).
228 */
229 private final HashMap<Account, AtomicReference<String>> previousNameCache =
230 new HashMap<Account, AtomicReference<String>>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800231
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700232 private int debugDbInsertionPoint = -1;
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700233 private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700234
Fyodor Kupoloveeca6582016-04-08 12:14:04 -0700235 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800236 this.userId = userId;
237 synchronized (cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700238 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800239 }
240 }
241 }
242
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700243 private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600244 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700245 // Not thread-safe. Only use in synchronized context
246 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Svet Ganovf6d424f12016-09-20 20:18:53 -0700247 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
248 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800249
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700250 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
Fred Quintana31957f12009-10-21 13:43:10 -0700251 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
Fred Quintana7be59642009-08-24 18:29:25 -0700252
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700253 /**
254 * This should only be called by system code. One should only call this after the service
255 * has started.
256 * @return a reference to the AccountManagerService instance
257 * @hide
258 */
259 public static AccountManagerService getSingleton() {
260 return sThis.get();
261 }
Fred Quintana60307342009-03-24 22:48:12 -0700262
Fyodor Kupolovda993802016-09-21 14:47:10 -0700263 public AccountManagerService(Injector injector) {
264 mInjector = injector;
265 mContext = injector.getContext();
266 mPackageManager = mContext.getPackageManager();
Svetoslavf3f02ac2015-09-08 14:36:35 -0700267 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Fyodor Kupolovda993802016-09-21 14:47:10 -0700268 mHandler = new MessageHandler(injector.getMessageHandlerLooper());
269 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800270 mAuthenticatorCache.setListener(this, null /* Handler */);
Fred Quintana60307342009-03-24 22:48:12 -0700271
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700272 sThis.set(this);
Fred Quintanaafa92b82009-12-01 16:27:03 -0800273
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800274 IntentFilter intentFilter = new IntentFilter();
275 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
276 intentFilter.addDataScheme("package");
277 mContext.registerReceiver(new BroadcastReceiver() {
278 @Override
279 public void onReceive(Context context1, Intent intent) {
Carlos Valdivia23f58262014-09-05 10:52:41 -0700280 // Don't delete accounts when updating a authenticator's
281 // package.
282 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700283 /* Purging data requires file io, don't block the main thread. This is probably
284 * less than ideal because we are introducing a race condition where old grants
285 * could be exercised until they are purged. But that race condition existed
286 * anyway with the broadcast receiver.
287 *
288 * Ideally, we would completely clear the cache, purge data from the database,
289 * and then rebuild the cache. All under the cache lock. But that change is too
290 * large at this point.
291 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800292 final String removedPackageName = intent.getData().toString();
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700293 Runnable purgingRunnable = new Runnable() {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700294 @Override
295 public void run() {
296 purgeOldGrantsAll();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800297 // Notify authenticator about removed app?
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800298 removeVisibilityValuesForPackage(removedPackageName);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -0700299 }
300 };
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700301 mHandler.post(purgingRunnable);
Carlos Valdivia23f58262014-09-05 10:52:41 -0700302 }
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800303 }
304 }, intentFilter);
Fred Quintanac1a4e5d2011-02-25 10:44:38 -0800305
Amith Yamasani13593602012-03-22 16:16:17 -0700306 IntentFilter userFilter = new IntentFilter();
307 userFilter.addAction(Intent.ACTION_USER_REMOVED);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800308 mContext.registerReceiverAsUser(new BroadcastReceiver() {
Amith Yamasani13593602012-03-22 16:16:17 -0700309 @Override
310 public void onReceive(Context context, Intent intent) {
Amith Yamasani67df64b2012-12-14 12:09:36 -0800311 String action = intent.getAction();
312 if (Intent.ACTION_USER_REMOVED.equals(action)) {
313 onUserRemoved(intent);
Amith Yamasani67df64b2012-12-14 12:09:36 -0800314 }
Amith Yamasani13593602012-03-22 16:16:17 -0700315 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800316 }, UserHandle.ALL, userFilter, null, null);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700317
Fyodor Kupolovda993802016-09-21 14:47:10 -0700318 injector.addLocalService(new AccountManagerInternalImpl());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700319
320 // Need to cancel account request notifications if the update/install can access the account
321 new PackageMonitor() {
322 @Override
323 public void onPackageAdded(String packageName, int uid) {
324 // Called on a handler, and running as the system
325 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
326 }
327
328 @Override
329 public void onPackageUpdateFinished(String packageName, int uid) {
330 // Called on a handler, and running as the system
331 cancelAccountAccessRequestNotificationIfNeeded(uid, true);
332 }
Fyodor Kupolov8873aa32016-08-25 15:25:40 -0700333 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700334
335 // Cancel account request notification if an app op was preventing the account access
336 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
337 new AppOpsManager.OnOpChangedInternalListener() {
338 @Override
339 public void onOpChanged(int op, String packageName) {
340 try {
341 final int userId = ActivityManager.getCurrentUser();
342 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
343 final int mode = mAppOpsManager.checkOpNoThrow(
344 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
345 if (mode == AppOpsManager.MODE_ALLOWED) {
346 final long identity = Binder.clearCallingIdentity();
347 try {
348 cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
349 } finally {
350 Binder.restoreCallingIdentity(identity);
351 }
352 }
353 } catch (NameNotFoundException e) {
354 /* ignore */
355 }
356 }
357 });
358
359 // Cancel account request notification if a permission was preventing the account access
360 mPackageManager.addOnPermissionsChangeListener(
361 (int uid) -> {
362 Account[] accounts = null;
363 String[] packageNames = mPackageManager.getPackagesForUid(uid);
364 if (packageNames != null) {
365 final int userId = UserHandle.getUserId(uid);
366 final long identity = Binder.clearCallingIdentity();
367 try {
368 for (String packageName : packageNames) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800369 // if app asked for permission we need to cancel notification even
370 // for O+ applications.
371 if (mPackageManager.checkPermission(
372 Manifest.permission.GET_ACCOUNTS,
373 packageName) != PackageManager.PERMISSION_GRANTED) {
374 continue;
375 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700376
377 if (accounts == null) {
378 accounts = getAccountsAsUser(null, userId, "android");
379 if (ArrayUtils.isEmpty(accounts)) {
380 return;
381 }
382 }
383
384 for (Account account : accounts) {
385 cancelAccountAccessRequestNotificationIfNeeded(
386 account, uid, packageName, true);
387 }
388 }
389 } finally {
390 Binder.restoreCallingIdentity(identity);
391 }
392 }
393 });
394 }
395
396 private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
397 boolean checkAccess) {
398 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
399 for (Account account : accounts) {
400 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
401 }
402 }
403
404 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
405 boolean checkAccess) {
406 Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
407 for (Account account : accounts) {
408 cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
409 }
410 }
411
412 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
413 boolean checkAccess) {
414 String[] packageNames = mPackageManager.getPackagesForUid(uid);
415 if (packageNames != null) {
416 for (String packageName : packageNames) {
417 cancelAccountAccessRequestNotificationIfNeeded(account, uid,
418 packageName, checkAccess);
419 }
420 }
421 }
422
423 private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
424 int uid, String packageName, boolean checkAccess) {
425 if (!checkAccess || hasAccountAccess(account, packageName,
426 UserHandle.getUserHandleForUid(uid))) {
427 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700428 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700429 UserHandle.getUserHandleForUid(uid));
430 }
Fred Quintanaafa92b82009-12-01 16:27:03 -0800431 }
432
Dianne Hackborn164371f2013-10-01 19:10:13 -0700433 @Override
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800434 public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800435 Bundle extras, Map packageToVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800436 Bundle.setDefusable(extras, true);
437
438 final int callingUid = Binder.getCallingUid();
439 if (Log.isLoggable(TAG, Log.VERBOSE)) {
440 Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
441 + ", pid " + Binder.getCallingPid());
442 }
443 Preconditions.checkNotNull(account, "account cannot be null");
444 int userId = UserHandle.getCallingUserId();
445 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
446 String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
447 callingUid, account.type);
448 throw new SecurityException(msg);
449 }
450 /*
451 * Child users are not allowed to add accounts. Only the accounts that are shared by the
452 * parent profile can be added to child profile.
453 *
454 * TODO: Only allow accounts that were shared to be added by a limited user.
455 */
456 // fails if the account already exists
457 long identityToken = clearCallingIdentity();
458 try {
459 UserAccounts accounts = getUserAccounts(userId);
460 return addAccountInternal(accounts, account, password, extras, callingUid,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800461 (Map<String, Integer>) packageToVisibility);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800462 } finally {
463 restoreCallingIdentity(identityToken);
464 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700465 }
466
467 @Override
Dmitry Dementyev52745472016-12-02 10:27:45 -0800468 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
469 String accountType) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800470 int callingUid = Binder.getCallingUid();
471 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
472 List<String> managedTypes =
473 getTypesForCaller(callingUid, UserHandle.getUserId(callingUid), isSystemUid);
474
475 if ((accountType != null && !managedTypes.contains(accountType))
476 || (accountType == null && !isSystemUid)) {
477 throw new SecurityException(
478 "getAccountsAndVisibilityForPackage() called from unauthorized uid "
479 + callingUid + " with packageName=" + packageName);
480 }
481 if (accountType != null) {
482 managedTypes = new ArrayList<String>();
483 managedTypes.add(accountType);
484 }
485
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800486 long identityToken = clearCallingIdentity();
487 try {
488 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
489 getUserAccounts(UserHandle.getUserId(callingUid)));
490 } finally {
491 restoreCallingIdentity(identityToken);
492 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800493 }
494
495 /*
496 * accountTypes may not be null
497 */
498 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
499 List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
500 int uid = 0;
501 try {
502 uid = mPackageManager.getPackageUidAsUser(packageName,
503 UserHandle.getUserId(callingUid));
504 } catch (NameNotFoundException e) {
505 Log.d(TAG, "Package not found " + e.getMessage());
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800506 return new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800507 }
508
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -0800509 Map<Account, Integer> result = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800510 for (String accountType : accountTypes) {
511 synchronized (accounts.cacheLock) {
512 final Account[] accountsOfType = accounts.accountCache.get(accountType);
513 if (accountsOfType != null) {
514 for (Account account : accountsOfType) {
515 result.put(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800516 resolveAccountVisibility(account, packageName, accounts));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800517 }
518 }
519 }
520 }
521 return filterSharedAccounts(accounts, result, callingUid, packageName);
Dmitry Dementyev52745472016-12-02 10:27:45 -0800522 }
523
524 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800525 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800526 if (account == null) throw new IllegalArgumentException("account is null");
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700527 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800528 int userId = UserHandle.getUserId(callingUid);
529 UserAccounts accounts = getUserAccounts(userId);
530 if (!isAccountManagedByCaller(account.type, callingUid, userId)
531 && !isSystemUid(callingUid)) {
532 String msg =
533 String.format("uid %s cannot get secrets for account %s", callingUid, account);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700534 throw new SecurityException(msg);
535 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800536 return getPackagesAndVisibilityForAccount(account, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800537 }
538
539 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800540 * Returns all package names and visibility values, which were set for given account.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800541 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800542 * @param account Account to get visibility values.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800543 * @param accounts UserAccount that currently hosts the account and application
544 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800545 * @return Map from package names to visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800546 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800547 private Map<String, Integer> getPackagesAndVisibilityForAccount(Account account,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800548 UserAccounts accounts) {
549 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
550 try {
551 return accounts.accountsDb.findAllVisibilityValuesForAccount(account);
552 } finally {
553 StrictMode.setThreadPolicy(oldPolicy);
554 }
555
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700556 }
557
558 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800559 public int getAccountVisibility(Account a, String packageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800560 if (a == null) throw new IllegalArgumentException("account is null");
561 int callingUid = Binder.getCallingUid();
562 if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
563 && !isSystemUid(callingUid)) {
564 String msg = String.format(
565 "uid %s cannot get secrets for accounts of type: %s",
566 callingUid,
567 a.type);
568 throw new SecurityException(msg);
569 }
Dmitry Dementyev06f32e02017-02-16 17:47:48 -0800570 return resolveAccountVisibility(a, packageName,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800571 getUserAccounts(UserHandle.getUserId(callingUid)));
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800572 }
573
574 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800575 * Method returns visibility for given account and package name.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800576 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800577 * @param account The account to check visibility.
578 * @param packageName Package name to check visibility.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800579 * @param accounts UserAccount that currently hosts the account and application
580 *
581 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
582 *
583 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800584 private int getAccountVisibility(Account account, String packageName, UserAccounts accounts) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800585 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
586 try {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800587 Integer visibility = accounts.accountsDb.findAccountVisibility(account, packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800588 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
589 } finally {
590 StrictMode.setThreadPolicy(oldPolicy);
591 }
592 }
593
594 /**
595 * Method which handles default values for Account visibility.
596 *
597 * @param account The account to check visibility.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800598 * @param packageName Package name to check visibility
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800599 * @param accounts UserAccount that currently hosts the account and application
600 *
601 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
602 *
603 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800604 private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800605 UserAccounts accounts) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800606 Preconditions.checkNotNull(packageName, "packageName cannot be null");
607
608 int uid = -1;
609 try {
610 long identityToken = clearCallingIdentity();
611 try {
612 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
613 } finally {
614 restoreCallingIdentity(identityToken);
615 }
616 } catch (NameNotFoundException e) {
617 Log.d(TAG, "Package not found " + e.getMessage());
618 return AccountManager.VISIBILITY_NOT_VISIBLE;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800619 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800620
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800621 // System visibility can not be restricted.
622 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
623 return AccountManager.VISIBILITY_VISIBLE;
624 }
625
626 int signatureCheckResult =
627 checkPackageSignature(account.type, uid, accounts.userId);
628
629 // Authenticator can not restrict visibility to itself.
630 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) {
631 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
632 }
633
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800634 if (isSpecialPackageKey(packageName)) {
635 Log.d(TAG, "Package name is forbidden: " + packageName);
636 return AccountManager.VISIBILITY_NOT_VISIBLE;
637 }
638
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800639 // Return stored value if it was set.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800640 int visibility = getAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800641
642 if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
643 return visibility;
644 }
645
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800646 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
647 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
648
649 // Device/Profile owner gets visibility by default.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800650 if (isProfileOwner(uid)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800651 return AccountManager.VISIBILITY_VISIBLE;
652 }
653 // Apps with READ_CONTACTS permission get visibility by default even post O.
654 boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId);
655
656 boolean preO = isPreOApplication(packageName);
657 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
658 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
Dmitry Dementyevf794c8d2017-02-03 18:17:59 -0800659 || canReadContacts || isPrivileged) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800660 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
661 // match.
662 visibility = getAccountVisibility(account,
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800663 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800664 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
665 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
666 }
667 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800668 visibility = getAccountVisibility(account,
669 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800670 if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
671 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
672 }
673 }
674 return visibility;
675 }
676
677 /**
678 * Checks targetSdk for a package;
679 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800680 * @param packageName Package name
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800681 *
682 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
683 * undefined
684 */
685 private boolean isPreOApplication(String packageName) {
686 try {
687 long identityToken = clearCallingIdentity();
688 ApplicationInfo applicationInfo;
689 try {
690 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
691 } finally {
692 restoreCallingIdentity(identityToken);
693 }
694
695 if (applicationInfo != null) {
696 int version = applicationInfo.targetSdkVersion;
697 return version < android.os.Build.VERSION_CODES.O;
698 }
699 return true;
700 } catch (NameNotFoundException e) {
701 Log.d(TAG, "Package not found " + e.getMessage());
702 return true;
703 }
Dmitry Dementyev58fa83622016-12-20 18:08:51 -0800704 }
705
706 @Override
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800707 public boolean setAccountVisibility(Account a, String packageName, int newVisibility) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800708 if (a == null) throw new IllegalArgumentException("account is null");
709 int callingUid = Binder.getCallingUid();
710 if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
711 && !isSystemUid(callingUid)) {
712 String msg = String.format(
713 "uid %s cannot get secrets for accounts of type: %s",
714 callingUid,
715 a.type);
716 throw new SecurityException(msg);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700717 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800718 return setAccountVisibility(a, packageName, newVisibility, true /* notify */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800719 getUserAccounts(UserHandle.getUserId(callingUid)));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700720 }
721
722 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800723 * Updates visibility for given account name and package.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700724 *
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800725 * @param account Account to update visibility.
726 * @param packageName Package name for which visibility is updated.
727 * @param newVisibility New visibility calue
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800728 * @param notify if the flag is set applications will get notification about visibility change
729 * @param accounts UserAccount that currently hosts the account and application
730 *
731 * @return True if account visibility was changed.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700732 */
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800733 private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800734 boolean notify, UserAccounts accounts) {
735 synchronized (accounts.cacheLock) {
736 LinkedHashSet<String> interestedPackages;
737 if (notify) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800738 if (isSpecialPackageKey(packageName)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800739 interestedPackages = getRequestingPackageNames(account.type, accounts);
740 } else {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800741 if (!packageExistsForUser(packageName, accounts.userId)) {
742 return false; // package is not installed.
Nicolas Prevotf7d8df12016-09-16 17:45:34 +0100743 }
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800744 interestedPackages = new LinkedHashSet<>();
745 interestedPackages.add(packageName);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800746 }
747 } else {
748 // Notifications will not be send.
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800749 if (!isSpecialPackageKey(packageName) &&
750 !packageExistsForUser(packageName, accounts.userId)) {
751 // package is not installed and not meta value.
752 return false;
753 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800754 interestedPackages = new LinkedHashSet<>();
755 }
756 Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
757
758 final long accountId = accounts.accountsDb.findDeAccountId(account);
759 if (accountId < 0) {
760 return false;
761 }
762 int index = 0;
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800763 for (String interestedPackage : interestedPackages) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800764 interestedPackagesVisibility[index++] =
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800765 resolveAccountVisibility(account, interestedPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800766 }
767
768 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
769 try {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800770 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
771 newVisibility)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800772 return false;
773 }
774 } finally {
775 StrictMode.setThreadPolicy(oldPolicy);
776 }
777
778 index = 0;
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800779 for (String interestedPackage : interestedPackages) {
780 int visibility = resolveAccountVisibility(account, interestedPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800781 if (visibility != interestedPackagesVisibility[index++]) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800782 sendNotification(interestedPackage, account, accounts.userId);
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700783 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700784 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800785 if (notify) {
786 sendAccountsChangedBroadcast(accounts.userId);
787 }
788 return true;
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700789 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700790 }
791
792 /**
Dmitry Dementyev52745472016-12-02 10:27:45 -0800793 * Sends a direct intent to a package, notifying it of a visible account change.
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700794 *
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800795 * @param packageName to send Account to
796 * @param account to send to package
797 * @param userId User
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700798 */
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800799 private void sendNotification(String packageName, Account account, int userId) {
800 // TODO send notification so apps subscribed in runtime.
801 }
802
803 private void sendNotification(Account account, UserAccounts accounts) {
804 LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
805 accounts);
806 for (String packageName : interestedPackages) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800807 int visibility = resolveAccountVisibility(account, packageName, accounts);
808 if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
809 sendNotification(packageName, account, accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800810 }
811 }
812 }
813
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800814 LinkedHashSet<String> getRequestingPackageNames(String accountType, UserAccounts accounts) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800815 // TODO return packages registered to get notifications.
816 return new LinkedHashSet<String>();
817 }
818
Dmitry Dementyeve366f822017-01-31 10:25:10 -0800819 private boolean packageExistsForUser(String packageName, int userId) {
820 try {
821 long identityToken = clearCallingIdentity();
822 try {
823 mPackageManager.getPackageUidAsUser(packageName, userId);
824 return true; // package exist
825 } finally {
826 restoreCallingIdentity(identityToken);
827 }
828 } catch (NameNotFoundException e) {
829 return false;
830 }
831 }
832
833 /**
834 * Returns true if packageName is one of special values.
835 */
836 private boolean isSpecialPackageKey(String packageName) {
837 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
838 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
839 }
840
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800841 private void sendAccountsChangedBroadcast(int userId) {
842 Log.i(TAG, "the accounts changed, sending broadcast of "
843 + ACCOUNTS_CHANGED_INTENT.getAction());
844 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700845 }
846
847 @Override
Dianne Hackborn164371f2013-10-01 19:10:13 -0700848 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
849 throws RemoteException {
850 try {
851 return super.onTransact(code, data, reply, flags);
852 } catch (RuntimeException e) {
853 // The account manager only throws security exceptions, so let's
854 // log all others.
855 if (!(e instanceof SecurityException)) {
856 Slog.wtf(TAG, "Account Manager Crash", e);
857 }
858 throw e;
859 }
860 }
861
Amith Yamasani258848d2012-08-10 17:06:33 -0700862 private UserManager getUserManager() {
863 if (mUserManager == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700864 mUserManager = UserManager.get(mContext);
Amith Yamasani258848d2012-08-10 17:06:33 -0700865 }
866 return mUserManager;
867 }
868
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700869 /**
870 * Validate internal set of accounts against installed authenticators for
871 * given user. Clears cached authenticators before validating.
872 */
873 public void validateAccounts(int userId) {
874 final UserAccounts accounts = getUserAccounts(userId);
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700875 // Invalidate user-specific cache to make sure we catch any
876 // removed authenticators.
877 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
878 }
879
880 /**
881 * Validate internal set of accounts against installed authenticators for
882 * given user. Clear cached authenticators before validating when requested.
883 */
884 private void validateAccountsInternal(
885 UserAccounts accounts, boolean invalidateAuthenticatorCache) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700886 if (Log.isLoggable(TAG, Log.DEBUG)) {
887 Log.d(TAG, "validateAccountsInternal " + accounts.userId
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700888 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600889 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700890 }
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700891
Jeff Sharkey6eb96202012-10-10 13:13:54 -0700892 if (invalidateAuthenticatorCache) {
893 mAuthenticatorCache.invalidateCache(accounts.userId);
894 }
895
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700896 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
897 mAuthenticatorCache, accounts.userId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700898 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700899
Amith Yamasani04e0d262012-02-14 11:50:53 -0800900 synchronized (accounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800901 boolean accountDeleted = false;
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800902
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700903 // Get a map of stored authenticator types to UID
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700904 final AccountsDb accountsDb = accounts.accountsDb;
905 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800906 // Create a list of authenticator type whose previous uid no longer exists
907 HashSet<String> obsoleteAuthType = Sets.newHashSet();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700908 SparseBooleanArray knownUids = null;
909 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
910 String type = authToUidEntry.getKey();
911 int uid = authToUidEntry.getValue();
912 Integer knownUid = knownAuth.get(type);
913 if (knownUid != null && uid == knownUid) {
914 // Remove it from the knownAuth list if it's unchanged.
915 knownAuth.remove(type);
916 } else {
917 /*
918 * The authenticator is presently not cached and should only be triggered
919 * when we think an authenticator has been removed (or is being updated).
920 * But we still want to check if any data with the associated uid is
921 * around. This is an (imperfect) signal that the package may be updating.
922 *
923 * A side effect of this is that an authenticator sharing a uid with
924 * multiple apps won't get its credentials wiped as long as some app with
925 * that uid is still on the device. But I suspect that this is a rare case.
926 * And it isn't clear to me how an attacker could really exploit that
927 * feature.
928 *
929 * The upshot is that we don't have to worry about accounts getting
930 * uninstalled while the authenticator's package is being updated.
931 *
932 */
933 if (knownUids == null) {
934 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800935 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700936 if (!knownUids.get(uid)) {
937 // The authenticator is not presently available to the cache. And the
938 // package no longer has a data directory (so we surmise it isn't updating).
939 // So purge its data from the account databases.
940 obsoleteAuthType.add(type);
941 // And delete it from the TABLE_META
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700942 accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800943 }
944 }
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800945 }
946
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700947 // Add the newly registered authenticator to TABLE_META. If old authenticators have
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700948 // been re-enabled (after being updated for example), then we just overwrite the old
Carlos Valdiviaa46b1122016-04-26 19:36:50 -0700949 // values.
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700950 for (Entry<String, Integer> entry : knownAuth.entrySet()) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700951 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
Sandra Kwan1c9026d2016-02-23 10:22:15 -0800952 }
953
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700954 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
Fred Quintanaf9f240e2011-02-24 18:27:50 -0800955 try {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800956 accounts.accountCache.clear();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700957 final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700958 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
959 final long accountId = accountEntry.getKey();
960 final Account account = accountEntry.getValue();
961 if (obsoleteAuthType.contains(account.type)) {
962 Slog.w(TAG, "deleting account " + account.name + " because type "
963 + account.type + "'s registered authenticator no longer exist.");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700964 accountsDb.beginTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700965 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700966 accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700967 // Also delete from CE table if user is unlocked; if user is currently
968 // locked the account will be removed later by syncDeCeAccountsLocked
969 if (userUnlocked) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700970 accountsDb.deleteCeAccount(accountId);
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700971 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700972 accountsDb.setTransactionSuccessful();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700973 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -0700974 accountsDb.endTransaction();
Fyodor Kupolov627fc202016-06-03 11:03:03 -0700975 }
Fred Quintana56285a62010-12-02 14:20:51 -0800976 accountDeleted = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700977
Fyodor Kupolov1ce01612016-08-26 11:39:07 -0700978 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
979 AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -0700980
Amith Yamasani04e0d262012-02-14 11:50:53 -0800981 accounts.userDataCache.remove(account);
982 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -0700983 accounts.accountTokenCaches.remove(account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -0800984 LinkedHashSet<String> interestedPackages =
985 getRequestingPackageNames(account.type, accounts);
986 for (String packageName : interestedPackages) {
987 sendNotification(packageName, null, accounts.userId);
988 }
989
Fred Quintana56285a62010-12-02 14:20:51 -0800990 } else {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700991 ArrayList<String> accountNames = accountNamesByType.get(account.type);
Fred Quintana56285a62010-12-02 14:20:51 -0800992 if (accountNames == null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -0700993 accountNames = new ArrayList<>();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700994 accountNamesByType.put(account.type, accountNames);
Fred Quintana56285a62010-12-02 14:20:51 -0800995 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -0700996 accountNames.add(account.name);
Fred Quintana56285a62010-12-02 14:20:51 -0800997 }
998 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -0700999 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
Fred Quintana56285a62010-12-02 14:20:51 -08001000 final String accountType = cur.getKey();
1001 final ArrayList<String> accountNames = cur.getValue();
1002 final Account[] accountsForType = new Account[accountNames.size()];
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001003 for (int i = 0; i < accountsForType.length; i++) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07001004 accountsForType[i] = new Account(accountNames.get(i), accountType,
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001005 UUID.randomUUID().toString());
Fred Quintana56285a62010-12-02 14:20:51 -08001006 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001007 accounts.accountCache.put(accountType, accountsForType);
Fred Quintanaafa92b82009-12-01 16:27:03 -08001008 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001009 } finally {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001010 if (accountDeleted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001011 sendAccountsChangedBroadcast(accounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001012 }
Fred Quintanaafa92b82009-12-01 16:27:03 -08001013 }
1014 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07001015 }
1016
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001017 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
1018 // Get the UIDs of all apps that might have data on the device. We want
1019 // to preserve user data if the app might otherwise be storing data.
1020 List<PackageInfo> pkgsWithData =
1021 mPackageManager.getInstalledPackagesAsUser(
1022 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
1023 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
1024 for (PackageInfo pkgInfo : pkgsWithData) {
1025 if (pkgInfo.applicationInfo != null
1026 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1027 knownUids.put(pkgInfo.applicationInfo.uid, true);
1028 }
1029 }
1030 return knownUids;
1031 }
1032
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001033 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001034 Context context,
1035 int userId) {
1036 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
Carlos Valdiviaa46b1122016-04-26 19:36:50 -07001037 return getAuthenticatorTypeAndUIDForUser(authCache, userId);
1038 }
1039
1040 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
1041 IAccountAuthenticatorCache authCache,
1042 int userId) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08001043 HashMap<String, Integer> knownAuth = new LinkedHashMap<>();
Sandra Kwan1c9026d2016-02-23 10:22:15 -08001044 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
1045 .getAllServices(userId)) {
1046 knownAuth.put(service.type.type, service.uid);
1047 }
1048 return knownAuth;
1049 }
1050
Amith Yamasani04e0d262012-02-14 11:50:53 -08001051 private UserAccounts getUserAccountsForCaller() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001052 return getUserAccounts(UserHandle.getCallingUserId());
Amith Yamasani04e0d262012-02-14 11:50:53 -08001053 }
1054
1055 protected UserAccounts getUserAccounts(int userId) {
1056 synchronized (mUsers) {
1057 UserAccounts accounts = mUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001058 boolean validateAccounts = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001059 if (accounts == null) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001060 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
1061 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001062 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001063 initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001064 mUsers.append(userId, accounts);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001065 purgeOldGrants(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001066 validateAccounts = true;
1067 }
1068 // open CE database if necessary
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001069 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001070 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
1071 synchronized (accounts.cacheLock) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001072 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001073 accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001074 }
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001075 syncDeCeAccountsLocked(accounts);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001076 }
1077 if (validateAccounts) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001078 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001079 }
1080 return accounts;
1081 }
1082 }
1083
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001084 private void syncDeCeAccountsLocked(UserAccounts accounts) {
1085 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001086 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001087 if (!accountsToRemove.isEmpty()) {
1088 Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
1089 + accounts.userId + " was locked. Removing accounts from CE tables");
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001090 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
1091 AccountsDb.TABLE_ACCOUNTS);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001092
1093 for (Account account : accountsToRemove) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001094 removeAccountInternal(accounts, account, Process.SYSTEM_UID);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001095 }
1096 }
1097 }
1098
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001099 private void purgeOldGrantsAll() {
1100 synchronized (mUsers) {
1101 for (int i = 0; i < mUsers.size(); i++) {
1102 purgeOldGrants(mUsers.valueAt(i));
1103 }
1104 }
1105 }
1106
1107 private void purgeOldGrants(UserAccounts accounts) {
1108 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001109 List<Integer> uids = accounts.accountsDb.findAllUidGrants();
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001110 for (int uid : uids) {
1111 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
1112 if (packageExists) {
1113 continue;
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001114 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001115 Log.d(TAG, "deleting grants for UID " + uid
1116 + " because its package is no longer installed");
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001117 accounts.accountsDb.deleteGrantsByUid(uid);
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07001118 }
1119 }
1120 }
1121
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001122 private void removeVisibilityValuesForPackage(String packageName) {
1123 synchronized (mUsers) {
1124 for (int i = 0; i < mUsers.size(); i++) {
1125 UserAccounts accounts = mUsers.valueAt(i);
1126 try {
1127 int uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
1128 } catch (NameNotFoundException e) {
1129 // package does not exist - remove visibility values
1130 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
1131 }
1132 }
1133 }
1134 }
1135
Amith Yamasani13593602012-03-22 16:16:17 -07001136 private void onUserRemoved(Intent intent) {
Amith Yamasani2a003292012-08-14 18:25:45 -07001137 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Amith Yamasani13593602012-03-22 16:16:17 -07001138 if (userId < 1) return;
1139
1140 UserAccounts accounts;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001141 boolean userUnlocked;
Amith Yamasani13593602012-03-22 16:16:17 -07001142 synchronized (mUsers) {
1143 accounts = mUsers.get(userId);
1144 mUsers.remove(userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001145 userUnlocked = mLocalUnlockedUsers.get(userId);
1146 mLocalUnlockedUsers.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001147 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001148 if (accounts != null) {
1149 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001150 accounts.accountsDb.close();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001151 }
Amith Yamasani13593602012-03-22 16:16:17 -07001152 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001153 Log.i(TAG, "Removing database files for user " + userId);
Fyodor Kupolovda993802016-09-21 14:47:10 -07001154 File dbFile = new File(mInjector.getDeDatabaseName(userId));
Amith Yamasani13593602012-03-22 16:16:17 -07001155
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001156 AccountsDb.deleteDbFileWarnIfFailed(dbFile);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001157 // Remove CE file if user is unlocked, or FBE is not enabled
1158 boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
1159 if (!fbeEnabled || userUnlocked) {
Fyodor Kupolovda993802016-09-21 14:47:10 -07001160 File ceDb = new File(mInjector.getCeDatabaseName(userId));
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001161 if (ceDb.exists()) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001162 AccountsDb.deleteDbFileWarnIfFailed(ceDb);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001163 }
1164 }
1165 }
1166
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07001167 @VisibleForTesting
1168 void onUserUnlocked(Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001169 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
1170 }
1171
1172 void onUnlockUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001173 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1174 Log.v(TAG, "onUserUnlocked " + userId);
1175 }
1176 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001177 mLocalUnlockedUsers.put(userId, true);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001178 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001179 if (userId < 1) return;
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001180 syncSharedAccounts(userId);
1181 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001182
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001183 private void syncSharedAccounts(int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001184 // Check if there's a shared account that needs to be created as an account
1185 Account[] sharedAccounts = getSharedAccountsAsUser(userId);
1186 if (sharedAccounts == null || sharedAccounts.length == 0) return;
Svetoslavf3f02ac2015-09-08 14:36:35 -07001187 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001188 int parentUserId = UserManager.isSplitSystemUser()
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001189 ? getUserManager().getUserInfo(userId).restrictedProfileParentId
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001190 : UserHandle.USER_SYSTEM;
1191 if (parentUserId < 0) {
1192 Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
1193 return;
1194 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001195 for (Account sa : sharedAccounts) {
1196 if (ArrayUtils.contains(accounts, sa)) continue;
1197 // Account doesn't exist. Copy it now.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001198 copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001199 }
1200 }
1201
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001202 @Override
1203 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001204 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
Fred Quintana60307342009-03-24 22:48:12 -07001205 }
1206
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001207 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07001208 public String getPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001209 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001210 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1211 Log.v(TAG, "getPassword: " + account
1212 + ", caller's uid " + Binder.getCallingUid()
1213 + ", pid " + Binder.getCallingPid());
1214 }
Fred Quintana382601f2010-03-25 12:25:10 -07001215 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001216 int userId = UserHandle.getCallingUserId();
1217 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001218 String msg = String.format(
1219 "uid %s cannot get secrets for accounts of type: %s",
1220 callingUid,
1221 account.type);
1222 throw new SecurityException(msg);
1223 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001224 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07001225 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001226 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001227 return readPasswordInternal(accounts, account);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001228 } finally {
1229 restoreCallingIdentity(identityToken);
1230 }
1231 }
1232
Amith Yamasani04e0d262012-02-14 11:50:53 -08001233 private String readPasswordInternal(UserAccounts accounts, Account account) {
Fred Quintana31957f12009-10-21 13:43:10 -07001234 if (account == null) {
1235 return null;
1236 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001237 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001238 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
1239 return null;
1240 }
Fred Quintana31957f12009-10-21 13:43:10 -07001241
Amith Yamasani04e0d262012-02-14 11:50:53 -08001242 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001243 return accounts.accountsDb.findAccountPasswordByNameAndType(account.name, account.type);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001244 }
1245 }
1246
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001247 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001248 public String getPreviousName(Account account) {
1249 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1250 Log.v(TAG, "getPreviousName: " + account
1251 + ", caller's uid " + Binder.getCallingUid()
1252 + ", pid " + Binder.getCallingPid());
1253 }
1254 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001255 int userId = UserHandle.getCallingUserId();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001256 long identityToken = clearCallingIdentity();
1257 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001258 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001259 return readPreviousNameInternal(accounts, account);
1260 } finally {
1261 restoreCallingIdentity(identityToken);
1262 }
1263 }
1264
1265 private String readPreviousNameInternal(UserAccounts accounts, Account account) {
1266 if (account == null) {
1267 return null;
1268 }
1269 synchronized (accounts.cacheLock) {
1270 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
1271 if (previousNameRef == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001272 String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001273 previousNameRef = new AtomicReference<>(previousName);
1274 accounts.previousNameCache.put(account, previousNameRef);
1275 return previousName;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001276 } else {
1277 return previousNameRef.get();
1278 }
1279 }
1280 }
1281
1282 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001283 public String getUserData(Account account, String key) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001284 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001285 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001286 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
1287 account, key, callingUid, Binder.getCallingPid());
1288 Log.v(TAG, msg);
Fred Quintana56285a62010-12-02 14:20:51 -08001289 }
Fred Quintana382601f2010-03-25 12:25:10 -07001290 if (account == null) throw new IllegalArgumentException("account is null");
1291 if (key == null) throw new IllegalArgumentException("key is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001292 int userId = UserHandle.getCallingUserId();
1293 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001294 String msg = String.format(
1295 "uid %s cannot get user data for accounts of type: %s",
1296 callingUid,
1297 account.type);
1298 throw new SecurityException(msg);
1299 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001300 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07001301 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
1302 return null;
1303 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001304 long identityToken = clearCallingIdentity();
1305 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001306 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00001307 synchronized (accounts.cacheLock) {
1308 if (!accountExistsCacheLocked(accounts, account)) {
1309 return null;
1310 }
1311 return readUserDataInternalLocked(accounts, account, key);
1312 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001313 } finally {
1314 restoreCallingIdentity(identityToken);
1315 }
1316 }
1317
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001318 @Override
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001319 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001320 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08001321 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1322 Log.v(TAG, "getAuthenticatorTypes: "
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001323 + "for user id " + userId
Fyodor Kupolov35f68082016-04-06 12:14:17 -07001324 + " caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001325 + ", pid " + Binder.getCallingPid());
1326 }
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001327 // Only allow the system process to read accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001328 if (isCrossUser(callingUid, userId)) {
1329 throw new SecurityException(
1330 String.format(
1331 "User %s tying to get authenticator types for %s" ,
1332 UserHandle.getCallingUserId(),
1333 userId));
1334 }
1335
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001336 final long identityToken = clearCallingIdentity();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001337 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001338 return getAuthenticatorTypesInternal(userId);
1339
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001340 } finally {
1341 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001342 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001343 }
1344
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001345 /**
1346 * Should only be called inside of a clearCallingIdentity block.
1347 */
1348 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
Fyodor Kupolov81446482016-08-24 11:27:49 -07001349 mAuthenticatorCache.updateServices(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001350 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
1351 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
1352 AuthenticatorDescription[] types =
1353 new AuthenticatorDescription[authenticatorCollection.size()];
1354 int i = 0;
1355 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
1356 : authenticatorCollection) {
1357 types[i] = authenticator.type;
1358 i++;
1359 }
1360 return types;
1361 }
1362
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001363 private boolean isCrossUser(int callingUid, int userId) {
1364 return (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001365 && callingUid != Process.SYSTEM_UID
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001366 && mContext.checkCallingOrSelfPermission(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001367 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1368 != PackageManager.PERMISSION_GRANTED);
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +01001369 }
1370
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001371 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07001372 public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001373 return addAccountExplicitlyWithVisibility(account, password, extras, null);
Fred Quintana60307342009-03-24 22:48:12 -07001374 }
1375
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001376 @Override
1377 public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001378 final int userFrom, int userTo) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001379 int callingUid = Binder.getCallingUid();
1380 if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
1381 throw new SecurityException("Calling copyAccountToUser requires "
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001382 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001383 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001384 final UserAccounts fromAccounts = getUserAccounts(userFrom);
1385 final UserAccounts toAccounts = getUserAccounts(userTo);
1386 if (fromAccounts == null || toAccounts == null) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001387 if (response != null) {
1388 Bundle result = new Bundle();
1389 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
1390 try {
1391 response.onResult(result);
1392 } catch (RemoteException e) {
1393 Slog.w(TAG, "Failed to report error back to the client." + e);
1394 }
1395 }
1396 return;
Amith Yamasani67df64b2012-12-14 12:09:36 -08001397 }
1398
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001399 Slog.d(TAG, "Copying account " + account.name
1400 + " from user " + userFrom + " to user " + userTo);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001401 long identityToken = clearCallingIdentity();
1402 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001403 new Session(fromAccounts, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001404 false /* stripAuthTokenFromResult */, account.name,
1405 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001406 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001407 protected String toDebugString(long now) {
1408 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1409 + ", " + account.type;
1410 }
1411
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001412 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001413 public void run() throws RemoteException {
1414 mAuthenticator.getAccountCredentialsForCloning(this, account);
1415 }
1416
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001417 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001418 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001419 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001420 if (result != null
1421 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
1422 // Create a Session for the target user and pass in the bundle
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001423 completeCloningAccount(response, result, account, toAccounts, userFrom);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001424 } else {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001425 super.onResult(result);
1426 }
1427 }
1428 }.bind();
1429 } finally {
1430 restoreCallingIdentity(identityToken);
1431 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001432 }
1433
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001434 @Override
1435 public boolean accountAuthenticated(final Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001436 final int callingUid = Binder.getCallingUid();
1437 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1438 String msg = String.format(
1439 "accountAuthenticated( account: %s, callerUid: %s)",
1440 account,
1441 callingUid);
1442 Log.v(TAG, msg);
1443 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001444 if (account == null) {
1445 throw new IllegalArgumentException("account is null");
1446 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001447 int userId = UserHandle.getCallingUserId();
1448 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001449 String msg = String.format(
1450 "uid %s cannot notify authentication for accounts of type: %s",
1451 callingUid,
1452 account.type);
1453 throw new SecurityException(msg);
1454 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001455
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001456 if (!canUserModifyAccounts(userId, callingUid) ||
1457 !canUserModifyAccountsForType(userId, account.type, callingUid)) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001458 return false;
1459 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001460
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001461 long identityToken = clearCallingIdentity();
1462 try {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001463 UserAccounts accounts = getUserAccounts(userId);
1464 return updateLastAuthenticatedTime(account);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001465 } finally {
1466 restoreCallingIdentity(identityToken);
1467 }
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07001468 }
1469
1470 private boolean updateLastAuthenticatedTime(Account account) {
1471 final UserAccounts accounts = getUserAccountsForCaller();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001472 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001473 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001474 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001475 }
1476
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001477 private void completeCloningAccount(IAccountManagerResponse response,
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001478 final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
1479 final int parentUserId){
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001480 Bundle.setDefusable(accountCredentials, true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001481 long id = clearCallingIdentity();
1482 try {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001483 new Session(targetUser, response, account.type, false,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001484 false /* stripAuthTokenFromResult */, account.name,
1485 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001486 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001487 protected String toDebugString(long now) {
1488 return super.toDebugString(now) + ", getAccountCredentialsForClone"
1489 + ", " + account.type;
1490 }
1491
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001492 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001493 public void run() throws RemoteException {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001494 // Confirm that the owner's account still exists before this step.
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001495 UserAccounts owner = getUserAccounts(parentUserId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001496 synchronized (owner.cacheLock) {
Svetoslavf3f02ac2015-09-08 14:36:35 -07001497 for (Account acc : getAccounts(parentUserId,
1498 mContext.getOpPackageName())) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001499 if (acc.equals(account)) {
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001500 mAuthenticator.addAccountFromCredentials(
1501 this, account, accountCredentials);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001502 break;
1503 }
1504 }
1505 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08001506 }
1507
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001508 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001509 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001510 Bundle.setDefusable(result, true);
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001511 // TODO: Anything to do if if succedded?
1512 // TODO: If it failed: Show error notification? Should we remove the shadow
1513 // account to avoid retries?
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001514 // TODO: what we do with the visibility?
1515
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001516 super.onResult(result);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001517 }
1518
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001519 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08001520 public void onError(int errorCode, String errorMessage) {
1521 super.onError(errorCode, errorMessage);
1522 // TODO: Show error notification to user
1523 // TODO: Should we remove the shadow account so that it doesn't keep trying?
1524 }
1525
1526 }.bind();
1527 } finally {
1528 restoreCallingIdentity(id);
1529 }
1530 }
1531
Amith Yamasani04e0d262012-02-14 11:50:53 -08001532 private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001533 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001534 Bundle.setDefusable(extras, true);
Fred Quintana743dfad2010-07-15 10:59:25 -07001535 if (account == null) {
1536 return false;
1537 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001538 if (!isLocalUnlockedUser(accounts.userId)) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001539 Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
1540 + " is locked. callingUid=" + callingUid);
1541 return false;
1542 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08001543 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001544 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001545 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001546 if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001547 Log.w(TAG, "insertAccountIntoDatabase: " + account
1548 + ", skipping since the account already exists");
1549 return false;
1550 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001551 long accountId = accounts.accountsDb.insertCeAccount(account, password);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001552 if (accountId < 0) {
1553 Log.w(TAG, "insertAccountIntoDatabase: " + account
1554 + ", skipping the DB insert failed");
1555 return false;
1556 }
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001557 // Insert into DE table
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001558 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001559 Log.w(TAG, "insertAccountIntoDatabase: " + account
1560 + ", skipping the DB insert failed");
1561 return false;
1562 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001563 if (extras != null) {
1564 for (String key : extras.keySet()) {
1565 final String value = extras.getString(key);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001566 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001567 Log.w(TAG, "insertAccountIntoDatabase: " + account
1568 + ", skipping since insertExtra failed for key " + key);
1569 return false;
1570 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001571 }
1572 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001573
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001574 if (packageToVisibility != null) {
1575 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
1576 setAccountVisibility(account, entry.getKey() /* package */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001577 entry.getValue() /* visibility */, false /* notify */, accounts);
1578 }
1579 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001580 accounts.accountsDb.setTransactionSuccessful();
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001581
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001582 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
1583 accounts, callingUid);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07001584
Amith Yamasani04e0d262012-02-14 11:50:53 -08001585 insertAccountIntoCacheLocked(accounts, account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08001586 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001587 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001588 }
Amith Yamasani5be347b2013-03-31 17:44:31 -07001589 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001590 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
1591 addAccountToLinkedRestrictedUsers(account, accounts.userId);
Amith Yamasani5be347b2013-03-31 17:44:31 -07001592 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001593
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001594 sendNotification(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001595 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
1596 sendAccountsChangedBroadcast(accounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001597
Amith Yamasani5be347b2013-03-31 17:44:31 -07001598 return true;
1599 }
1600
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001601 private boolean isLocalUnlockedUser(int userId) {
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001602 synchronized (mUsers) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001603 return mLocalUnlockedUsers.get(userId);
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001604 }
1605 }
1606
Amith Yamasani5be347b2013-03-31 17:44:31 -07001607 /**
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001608 * Adds the account to all linked restricted users as shared accounts. If the user is currently
Amith Yamasani5be347b2013-03-31 17:44:31 -07001609 * running, then clone the account too.
1610 * @param account the account to share with limited users
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001611 *
Amith Yamasani5be347b2013-03-31 17:44:31 -07001612 */
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001613 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
Mita Yunf4c240e2013-04-01 21:12:43 -07001614 List<UserInfo> users = getUserManager().getUsers();
Amith Yamasani5be347b2013-03-31 17:44:31 -07001615 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001616 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
Amith Yamasani5be347b2013-03-31 17:44:31 -07001617 addSharedAccountAsUser(account, user.id);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001618 if (isLocalUnlockedUser(user.id)) {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07001619 mHandler.sendMessage(mHandler.obtainMessage(
Fyodor Kupolov041232a2016-02-22 15:01:45 -08001620 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
Amith Yamasani5be347b2013-03-31 17:44:31 -07001621 }
1622 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001623 }
1624 }
1625
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001626 @Override
Fred Quintana3084a6f2010-01-14 18:02:03 -08001627 public void hasFeatures(IAccountManagerResponse response,
Svetoslavf3f02ac2015-09-08 14:36:35 -07001628 Account account, String[] features, String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001629 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08001630 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08001631 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1632 Log.v(TAG, "hasFeatures: " + account
1633 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001634 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001635 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08001636 + ", pid " + Binder.getCallingPid());
1637 }
Fred Quintana382601f2010-03-25 12:25:10 -07001638 if (response == null) throw new IllegalArgumentException("response is null");
1639 if (account == null) throw new IllegalArgumentException("account is null");
1640 if (features == null) throw new IllegalArgumentException("features is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001641 int userId = UserHandle.getCallingUserId();
Svetoslavf3f02ac2015-09-08 14:36:35 -07001642 checkReadAccountsPermitted(callingUid, account.type, userId,
1643 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001644
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001645 long identityToken = clearCallingIdentity();
1646 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001647 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001648 new TestFeaturesSession(accounts, response, account, features).bind();
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001649 } finally {
1650 restoreCallingIdentity(identityToken);
1651 }
1652 }
1653
1654 private class TestFeaturesSession extends Session {
1655 private final String[] mFeatures;
1656 private final Account mAccount;
1657
Amith Yamasani04e0d262012-02-14 11:50:53 -08001658 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001659 Account account, String[] features) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001660 super(accounts, response, account.type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001661 true /* stripAuthTokenFromResult */, account.name,
1662 false /* authDetailsRequired */);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001663 mFeatures = features;
1664 mAccount = account;
1665 }
1666
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001667 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001668 public void run() throws RemoteException {
1669 try {
1670 mAuthenticator.hasFeatures(this, mAccount, mFeatures);
1671 } catch (RemoteException e) {
1672 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1673 }
1674 }
1675
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001676 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001677 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001678 Bundle.setDefusable(result, true);
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001679 IAccountManagerResponse response = getResponseAndClose();
1680 if (response != null) {
1681 try {
1682 if (result == null) {
Fred Quintana166466d2011-10-24 14:51:40 -07001683 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001684 return;
1685 }
Fred Quintana56285a62010-12-02 14:20:51 -08001686 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1687 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
1688 + response);
1689 }
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001690 final Bundle newResult = new Bundle();
1691 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
1692 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
1693 response.onResult(newResult);
1694 } catch (RemoteException e) {
1695 // if the caller is dead then there is no one to care about remote exceptions
1696 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1697 Log.v(TAG, "failure while notifying response", e);
1698 }
1699 }
1700 }
1701 }
1702
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001703 @Override
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001704 protected String toDebugString(long now) {
Fred Quintana3084a6f2010-01-14 18:02:03 -08001705 return super.toDebugString(now) + ", hasFeatures"
Fred Quintanabb68a4f2010-01-13 17:28:39 -08001706 + ", " + mAccount
1707 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
1708 }
1709 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001710
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08001711 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001712 public void renameAccount(
1713 IAccountManagerResponse response, Account accountToRename, String newName) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001714 final int callingUid = Binder.getCallingUid();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001715 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1716 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001717 + ", caller's uid " + callingUid
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001718 + ", pid " + Binder.getCallingPid());
1719 }
1720 if (accountToRename == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001721 int userId = UserHandle.getCallingUserId();
1722 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001723 String msg = String.format(
1724 "uid %s cannot rename accounts of type: %s",
1725 callingUid,
1726 accountToRename.type);
1727 throw new SecurityException(msg);
1728 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001729 long identityToken = clearCallingIdentity();
1730 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001731 UserAccounts accounts = getUserAccounts(userId);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001732 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001733 Bundle result = new Bundle();
1734 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
1735 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07001736 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
1737 resultingAccount.getAccessId());
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001738 try {
1739 response.onResult(result);
1740 } catch (RemoteException e) {
1741 Log.w(TAG, e.getMessage());
1742 }
1743 } finally {
1744 restoreCallingIdentity(identityToken);
1745 }
1746 }
1747
1748 private Account renameAccountInternal(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001749 UserAccounts accounts, Account accountToRename, String newName) {
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001750 Account resultAccount = null;
1751 /*
1752 * Cancel existing notifications. Let authenticators
1753 * re-post notifications as required. But we don't know if
1754 * the authenticators have bound their notifications to
1755 * now stale account name data.
1756 *
1757 * With a rename api, we might not need to do this anymore but it
1758 * shouldn't hurt.
1759 */
1760 cancelNotification(
1761 getSigninRequiredNotificationId(accounts, accountToRename),
1762 new UserHandle(accounts.userId));
1763 synchronized(accounts.credentialsPermissionNotificationIds) {
1764 for (Pair<Pair<Account, String>, Integer> pair:
1765 accounts.credentialsPermissionNotificationIds.keySet()) {
1766 if (accountToRename.equals(pair.first.first)) {
1767 int id = accounts.credentialsPermissionNotificationIds.get(pair);
1768 cancelNotification(id, new UserHandle(accounts.userId));
1769 }
1770 }
1771 }
1772 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001773 accounts.accountsDb.beginTransaction();
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001774 Account renamedAccount = new Account(newName, accountToRename.type);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001775 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
1776 Log.e(TAG, "renameAccount failed - account with new name already exists");
1777 return null;
1778 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001779 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001780 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001781 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001782 accounts.accountsDb.renameCeAccount(accountId, newName);
Dmitry Dementyevcf50dcf2016-11-17 14:14:11 -08001783 if (accounts.accountsDb.renameDeAccount(
1784 accountId, newName, accountToRename.name)) {
1785 accounts.accountsDb.setTransactionSuccessful();
1786 } else {
1787 Log.e(TAG, "renameAccount failed");
1788 return null;
1789 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001790 } else {
1791 Log.e(TAG, "renameAccount failed - old account does not exist");
1792 return null;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001793 }
1794 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001795 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001796 }
1797 /*
1798 * Database transaction was successful. Clean up cached
1799 * data associated with the account in the user profile.
1800 */
Svet Ganov5c4a5122016-09-23 19:29:11 -07001801 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001802 /*
1803 * Extract the data and token caches before removing the
1804 * old account to preserve the user data associated with
1805 * the account.
1806 */
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001807 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
1808 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001809 removeAccountFromCacheLocked(accounts, accountToRename);
1810 /*
1811 * Update the cached data associated with the renamed
1812 * account.
1813 */
1814 accounts.userDataCache.put(renamedAccount, tmpData);
1815 accounts.authTokenCache.put(renamedAccount, tmpTokens);
1816 accounts.previousNameCache.put(
1817 renamedAccount,
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07001818 new AtomicReference<>(accountToRename.name));
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001819 resultAccount = renamedAccount;
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001820
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001821 int parentUserId = accounts.userId;
1822 if (canHaveProfile(parentUserId)) {
1823 /*
1824 * Owner or system user account was renamed, rename the account for
1825 * those users with which the account was shared.
1826 */
1827 List<UserInfo> users = getUserManager().getUsers(true);
1828 for (UserInfo user : users) {
1829 if (user.isRestricted()
1830 && (user.restrictedProfileParentId == parentUserId)) {
1831 renameSharedAccountAsUser(accountToRename, newName, user.id);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001832 }
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001833 }
1834 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08001835
1836 // Notify authenticator.
1837 sendNotification(resultAccount, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07001838 sendAccountsChangedBroadcast(accounts.userId);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001839 }
1840 return resultAccount;
1841 }
1842
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001843 private boolean canHaveProfile(final int parentUserId) {
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07001844 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001845 return userInfo != null && userInfo.canHaveProfile();
1846 }
1847
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07001848 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001849 public void removeAccount(IAccountManagerResponse response, Account account,
1850 boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001851 removeAccountAsUser(
1852 response,
1853 account,
1854 expectActivityLaunch,
1855 UserHandle.getCallingUserId());
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001856 }
1857
1858 @Override
1859 public void removeAccountAsUser(IAccountManagerResponse response, Account account,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001860 boolean expectActivityLaunch, int userId) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001861 final int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001862 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1863 Log.v(TAG, "removeAccount: " + account
1864 + ", response " + response
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001865 + ", caller's uid " + callingUid
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001866 + ", pid " + Binder.getCallingPid()
1867 + ", for user id " + userId);
1868 }
1869 if (response == null) throw new IllegalArgumentException("response is null");
1870 if (account == null) throw new IllegalArgumentException("account is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001871 // Only allow the system process to modify accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07001872 if (isCrossUser(callingUid, userId)) {
1873 throw new SecurityException(
1874 String.format(
1875 "User %s tying remove account for %s" ,
1876 UserHandle.getCallingUserId(),
1877 userId));
1878 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001879 /*
1880 * Only the system or authenticator should be allowed to remove accounts for that
1881 * authenticator. This will let users remove accounts (via Settings in the system) but not
1882 * arbitrary applications (like competing authenticators).
1883 */
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07001884 UserHandle user = UserHandle.of(userId);
Ian Pedowitz358e51f2016-03-15 17:08:27 +00001885 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
1886 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001887 String msg = String.format(
1888 "uid %s cannot remove accounts of type: %s",
1889 callingUid,
1890 account.type);
1891 throw new SecurityException(msg);
1892 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001893 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001894 try {
1895 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
1896 "User cannot modify accounts");
1897 } catch (RemoteException re) {
1898 }
1899 return;
1900 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00001901 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001902 try {
1903 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
1904 "User cannot modify accounts of this type (policy).");
1905 } catch (RemoteException re) {
1906 }
1907 return;
1908 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001909 long identityToken = clearCallingIdentity();
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07001910 UserAccounts accounts = getUserAccounts(userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001911 cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
Amith Yamasani04e0d262012-02-14 11:50:53 -08001912 synchronized(accounts.credentialsPermissionNotificationIds) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001913 for (Pair<Pair<Account, String>, Integer> pair:
Amith Yamasani04e0d262012-02-14 11:50:53 -08001914 accounts.credentialsPermissionNotificationIds.keySet()) {
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001915 if (account.equals(pair.first.first)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08001916 int id = accounts.credentialsPermissionNotificationIds.get(pair);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001917 cancelNotification(id, user);
Costin Manolacheec0c4f42010-11-16 09:57:28 -08001918 }
1919 }
1920 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001921 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001922 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001923 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1924 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001925 accountId,
1926 accounts,
1927 callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001928 try {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001929 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
1930 } finally {
1931 restoreCallingIdentity(identityToken);
1932 }
1933 }
1934
1935 @Override
1936 public boolean removeAccountExplicitly(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001937 final int callingUid = Binder.getCallingUid();
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001938 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1939 Log.v(TAG, "removeAccountExplicitly: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001940 + ", caller's uid " + callingUid
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001941 + ", pid " + Binder.getCallingPid());
1942 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001943 int userId = Binder.getCallingUserHandle().getIdentifier();
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001944 if (account == null) {
1945 /*
1946 * Null accounts should result in returning false, as per
1947 * AccountManage.addAccountExplicitly(...) java doc.
1948 */
1949 Log.e(TAG, "account is null");
1950 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001951 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001952 String msg = String.format(
1953 "uid %s cannot explicitly add accounts of type: %s",
1954 callingUid,
1955 account.type);
1956 throw new SecurityException(msg);
1957 }
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001958 UserAccounts accounts = getUserAccountsForCaller();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07001959 final long accountId = accounts.accountsDb.findDeAccountId(account);
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001960 logRecord(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07001961 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
1962 AccountsDb.TABLE_ACCOUNTS,
Dmitry Dementyeve59fc5f2016-07-08 10:46:22 -07001963 accountId,
1964 accounts,
1965 callingUid);
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001966 long identityToken = clearCallingIdentity();
1967 try {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07001968 return removeAccountInternal(accounts, account, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07001969 } finally {
1970 restoreCallingIdentity(identityToken);
Fred Quintanaa698f422009-04-08 19:14:54 -07001971 }
Fred Quintana60307342009-03-24 22:48:12 -07001972 }
1973
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001974 private class RemoveAccountSession extends Session {
1975 final Account mAccount;
Amith Yamasani04e0d262012-02-14 11:50:53 -08001976 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001977 Account account, boolean expectActivityLaunch) {
1978 super(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001979 true /* stripAuthTokenFromResult */, account.name,
1980 false /* authDetailsRequired */);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001981 mAccount = account;
1982 }
1983
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001984 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001985 protected String toDebugString(long now) {
1986 return super.toDebugString(now) + ", removeAccount"
1987 + ", account " + mAccount;
1988 }
1989
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001990 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001991 public void run() throws RemoteException {
1992 mAuthenticator.getAccountRemovalAllowed(this, mAccount);
1993 }
1994
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07001995 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001996 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001997 Bundle.setDefusable(result, true);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001998 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
1999 && !result.containsKey(AccountManager.KEY_INTENT)) {
2000 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002001 if (removalAllowed) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002002 removeAccountInternal(mAccounts, mAccount, getCallingUid());
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002003 }
2004 IAccountManagerResponse response = getResponseAndClose();
2005 if (response != null) {
Fred Quintana56285a62010-12-02 14:20:51 -08002006 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2007 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2008 + response);
2009 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002010 Bundle result2 = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002011 result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002012 try {
2013 response.onResult(result2);
2014 } catch (RemoteException e) {
2015 // ignore
2016 }
2017 }
2018 }
2019 super.onResult(result);
2020 }
2021 }
2022
Fyodor Kupoloveeca6582016-04-08 12:14:04 -07002023 @VisibleForTesting
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002024 protected void removeAccountInternal(Account account) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002025 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
Amith Yamasani04e0d262012-02-14 11:50:53 -08002026 }
2027
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002028 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002029 boolean isChanged = false;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002030 boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002031 if (!userUnlocked) {
2032 Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
2033 + " is still locked. CE data will be removed later");
2034 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08002035 synchronized (accounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002036 LinkedHashSet<String> interestedPackages =
2037 accounts.mApplicationAccountRequestMappings.get(account.type);
2038 if (interestedPackages == null) {
2039 interestedPackages = new LinkedHashSet<>();
2040 }
2041 int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
2042 int index = 0;
2043 for (String packageName : interestedPackages) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08002044 int visibility = resolveAccountVisibility(account, packageName, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002045 visibilityForInterestedPackages[index++] = visibility;
2046 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002047 accounts.accountsDb.beginTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002048 // Set to a dummy value, this will only be used if the database
2049 // transaction succeeds.
2050 long accountId = -1;
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002051 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002052 accountId = accounts.accountsDb.findDeAccountId(account);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002053 if (accountId >= 0) {
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002054 isChanged = accounts.accountsDb.deleteDeAccount(accountId);
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002055 }
Fyodor Kupolov98e9e852016-12-09 14:58:05 -08002056 // always delete from CE table if CE storage is available
2057 // DE account could be removed while CE was locked
2058 if (userUnlocked) {
2059 long ceAccountId = accounts.accountsDb.findCeAccountId(account);
2060 if (ceAccountId >= 0) {
2061 accounts.accountsDb.deleteCeAccount(ceAccountId);
2062 }
2063 }
2064 accounts.accountsDb.setTransactionSuccessful();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002065 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002066 accounts.accountsDb.endTransaction();
Fyodor Kupolov35f68082016-04-06 12:14:17 -07002067 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002068 if (isChanged) {
2069 removeAccountFromCacheLocked(accounts, account);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002070 index = 0;
2071 for (String packageName : interestedPackages) {
2072 if ((visibilityForInterestedPackages[index]
2073 != AccountManager.VISIBILITY_NOT_VISIBLE)
2074 && (visibilityForInterestedPackages[index]
2075 != AccountManager.VISIBILITY_UNDEFINED)) {
2076 sendNotification(packageName, account, accounts.userId);
2077 }
2078 ++index;
2079 }
2080
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002081 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
2082 sendAccountsChangedBroadcast(accounts.userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002083 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
2084 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
2085 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002086 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002087 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002088 long id = Binder.clearCallingIdentity();
2089 try {
2090 int parentUserId = accounts.userId;
2091 if (canHaveProfile(parentUserId)) {
2092 // Remove from any restricted profiles that are sharing this account.
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07002093 List<UserInfo> users = getUserManager().getUsers(true);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002094 for (UserInfo user : users) {
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002095 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002096 removeSharedAccountAsUser(account, user.id, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002097 }
2098 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08002099 }
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07002100 } finally {
2101 Binder.restoreCallingIdentity(id);
Amith Yamasani67df64b2012-12-14 12:09:36 -08002102 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002103
2104 if (isChanged) {
2105 synchronized (accounts.credentialsPermissionNotificationIds) {
2106 for (Pair<Pair<Account, String>, Integer> key
2107 : accounts.credentialsPermissionNotificationIds.keySet()) {
2108 if (account.equals(key.first.first)
Svet Ganovf6d424f12016-09-20 20:18:53 -07002109 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002110 final int uid = (Integer) key.second;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07002111 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002112 account, uid, false));
2113 }
2114 }
2115 }
2116 }
2117
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002118 return isChanged;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002119 }
2120
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002121 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002122 public void invalidateAuthToken(String accountType, String authToken) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002123 int callerUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002124 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2125 Log.v(TAG, "invalidateAuthToken: accountType " + accountType
Carlos Valdivia91979be2015-05-22 14:11:35 -07002126 + ", caller's uid " + callerUid
Fred Quintana56285a62010-12-02 14:20:51 -08002127 + ", pid " + Binder.getCallingPid());
2128 }
Fred Quintana382601f2010-03-25 12:25:10 -07002129 if (accountType == null) throw new IllegalArgumentException("accountType is null");
2130 if (authToken == null) throw new IllegalArgumentException("authToken is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002131 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002132 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002133 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002134 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002135 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002136 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002137 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002138 invalidateAuthTokenLocked(accounts, accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002139 invalidateCustomTokenLocked(accounts, accountType, authToken);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002140 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002141 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002142 accounts.accountsDb.endTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002143 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002144 }
Fred Quintana60307342009-03-24 22:48:12 -07002145 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002146 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002147 }
2148 }
2149
Carlos Valdivia91979be2015-05-22 14:11:35 -07002150 private void invalidateCustomTokenLocked(
2151 UserAccounts accounts,
2152 String accountType,
2153 String authToken) {
2154 if (authToken == null || accountType == null) {
2155 return;
2156 }
2157 // Also wipe out cached token in memory.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002158 accounts.accountTokenCaches.remove(accountType, authToken);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002159 }
2160
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002161 private void invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
2162 String authToken) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002163 if (authToken == null || accountType == null) {
2164 return;
2165 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002166 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
Fred Quintana33269202009-04-20 16:05:10 -07002167 try {
2168 while (cursor.moveToNext()) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002169 String authTokenId = cursor.getString(0);
Fred Quintana33269202009-04-20 16:05:10 -07002170 String accountName = cursor.getString(1);
2171 String authTokenType = cursor.getString(2);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002172 accounts.accountsDb.deleteAuthToken(authTokenId);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002173 writeAuthTokenIntoCacheLocked(
2174 accounts,
Carlos Valdivia91979be2015-05-22 14:11:35 -07002175 new Account(accountName, accountType),
2176 authTokenType,
2177 null);
Fred Quintana60307342009-03-24 22:48:12 -07002178 }
Fred Quintana33269202009-04-20 16:05:10 -07002179 } finally {
2180 cursor.close();
Fred Quintana60307342009-03-24 22:48:12 -07002181 }
2182 }
2183
Carlos Valdivia91979be2015-05-22 14:11:35 -07002184 private void saveCachedToken(
2185 UserAccounts accounts,
2186 Account account,
2187 String callerPkg,
2188 byte[] callerSigDigest,
2189 String tokenType,
2190 String token,
2191 long expiryMillis) {
2192
2193 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
2194 return;
2195 }
2196 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002197 UserHandle.of(accounts.userId));
Carlos Valdivia91979be2015-05-22 14:11:35 -07002198 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002199 accounts.accountTokenCaches.put(
2200 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002201 }
2202 }
2203
Amith Yamasani04e0d262012-02-14 11:50:53 -08002204 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
2205 String authToken) {
Fred Quintana31957f12009-10-21 13:43:10 -07002206 if (account == null || type == null) {
2207 return false;
2208 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002209 cancelNotification(getSigninRequiredNotificationId(accounts, account),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07002210 UserHandle.of(accounts.userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002211 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002212 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002213 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002214 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002215 if (accountId < 0) {
2216 return false;
2217 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002218 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
2219 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
2220 accounts.accountsDb.setTransactionSuccessful();
2221 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002222 return true;
2223 }
Fred Quintana33269202009-04-20 16:05:10 -07002224 return false;
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002225 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002226 accounts.accountsDb.endTransaction();
Fred Quintana33269202009-04-20 16:05:10 -07002227 }
Fred Quintana60307342009-03-24 22:48:12 -07002228 }
2229 }
2230
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002231 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002232 public String peekAuthToken(Account account, String authTokenType) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002233 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002234 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2235 Log.v(TAG, "peekAuthToken: " + account
2236 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002237 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002238 + ", pid " + Binder.getCallingPid());
2239 }
Fred Quintana382601f2010-03-25 12:25:10 -07002240 if (account == null) throw new IllegalArgumentException("account is null");
2241 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002242 int userId = UserHandle.getCallingUserId();
2243 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002244 String msg = String.format(
2245 "uid %s cannot peek the authtokens associated with accounts of type: %s",
2246 callingUid,
2247 account.type);
2248 throw new SecurityException(msg);
2249 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002250 if (!isLocalUnlockedUser(userId)) {
Fyodor Kupolovc86c3fd2016-04-18 13:57:31 -07002251 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid "
2252 + callingUid);
2253 return null;
2254 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002255 long identityToken = clearCallingIdentity();
2256 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002257 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002258 return readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002259 } finally {
2260 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002261 }
Fred Quintana60307342009-03-24 22:48:12 -07002262 }
2263
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002264 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002265 public void setAuthToken(Account account, String authTokenType, String authToken) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002266 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002267 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2268 Log.v(TAG, "setAuthToken: " + account
2269 + ", authTokenType " + authTokenType
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002270 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002271 + ", pid " + Binder.getCallingPid());
2272 }
Fred Quintana382601f2010-03-25 12:25:10 -07002273 if (account == null) throw new IllegalArgumentException("account is null");
2274 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002275 int userId = UserHandle.getCallingUserId();
2276 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002277 String msg = String.format(
2278 "uid %s cannot set auth tokens associated with accounts of type: %s",
2279 callingUid,
2280 account.type);
2281 throw new SecurityException(msg);
2282 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002283 long identityToken = clearCallingIdentity();
2284 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002285 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002286 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002287 } finally {
2288 restoreCallingIdentity(identityToken);
2289 }
Fred Quintana60307342009-03-24 22:48:12 -07002290 }
2291
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002292 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002293 public void setPassword(Account account, String password) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002294 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002295 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2296 Log.v(TAG, "setAuthToken: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002297 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002298 + ", pid " + Binder.getCallingPid());
2299 }
Fred Quintana382601f2010-03-25 12:25:10 -07002300 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002301 int userId = UserHandle.getCallingUserId();
2302 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002303 String msg = String.format(
2304 "uid %s cannot set secrets for accounts of type: %s",
2305 callingUid,
2306 account.type);
2307 throw new SecurityException(msg);
2308 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002309 long identityToken = clearCallingIdentity();
2310 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002311 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002312 setPasswordInternal(accounts, account, password, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002313 } finally {
2314 restoreCallingIdentity(identityToken);
2315 }
Fred Quintana60307342009-03-24 22:48:12 -07002316 }
2317
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002318 private void setPasswordInternal(UserAccounts accounts, Account account, String password,
2319 int callingUid) {
Fred Quintana31957f12009-10-21 13:43:10 -07002320 if (account == null) {
2321 return;
2322 }
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002323 boolean isChanged = false;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002324 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002325 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002326 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002327 final long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002328 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002329 accounts.accountsDb.updateCeAccountPassword(accountId, password);
2330 accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002331 accounts.authTokenCache.remove(account);
Carlos Valdivia91979be2015-05-22 14:11:35 -07002332 accounts.accountTokenCaches.remove(account);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002333 accounts.accountsDb.setTransactionSuccessful();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002334 // If there is an account whose password will be updated and the database
2335 // transactions succeed, then we say that a change has occured. Even if the
2336 // new password is the same as the old and there were no authtokens to delete.
2337 isChanged = true;
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002338 String action = (password == null || password.length() == 0) ?
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002339 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
2340 : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
2341 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
Costin Manolachef5ffe892011-01-19 09:35:32 -08002342 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08002343 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002344 accounts.accountsDb.endTransaction();
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002345 if (isChanged) {
2346 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002347 sendNotification(account, accounts);
Carlos Valdivia98b5f9d2016-07-07 17:47:12 -07002348 sendAccountsChangedBroadcast(accounts.userId);
2349 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002350 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08002351 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -07002352 }
2353
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002354 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002355 public void clearPassword(Account account) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002356 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002357 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2358 Log.v(TAG, "clearPassword: " + account
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002359 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002360 + ", pid " + Binder.getCallingPid());
2361 }
Fred Quintana382601f2010-03-25 12:25:10 -07002362 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002363 int userId = UserHandle.getCallingUserId();
2364 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002365 String msg = String.format(
2366 "uid %s cannot clear passwords for accounts of type: %s",
2367 callingUid,
2368 account.type);
2369 throw new SecurityException(msg);
2370 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002371 long identityToken = clearCallingIdentity();
2372 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002373 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07002374 setPasswordInternal(accounts, account, null, callingUid);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002375 } finally {
2376 restoreCallingIdentity(identityToken);
2377 }
Fred Quintana60307342009-03-24 22:48:12 -07002378 }
2379
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002380 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07002381 public void setUserData(Account account, String key, String value) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002382 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08002383 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2384 Log.v(TAG, "setUserData: " + account
2385 + ", key " + key
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002386 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08002387 + ", pid " + Binder.getCallingPid());
2388 }
Fred Quintana382601f2010-03-25 12:25:10 -07002389 if (key == null) throw new IllegalArgumentException("key is null");
2390 if (account == null) throw new IllegalArgumentException("account is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002391 int userId = UserHandle.getCallingUserId();
2392 if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07002393 String msg = String.format(
2394 "uid %s cannot set user data for accounts of type: %s",
2395 callingUid,
2396 account.type);
2397 throw new SecurityException(msg);
2398 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002399 long identityToken = clearCallingIdentity();
Fred Quintana60307342009-03-24 22:48:12 -07002400 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002401 UserAccounts accounts = getUserAccounts(userId);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002402 synchronized (accounts.cacheLock) {
2403 if (!accountExistsCacheLocked(accounts, account)) {
2404 return;
2405 }
2406 setUserdataInternalLocked(accounts, account, key, value);
2407 }
Fred Quintana60307342009-03-24 22:48:12 -07002408 } finally {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002409 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07002410 }
2411 }
2412
Simranjit Kohli858511c2016-03-10 18:36:11 +00002413 private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
2414 if (accounts.accountCache.containsKey(account.type)) {
2415 for (Account acc : accounts.accountCache.get(account.type)) {
2416 if (acc.name.equals(account.name)) {
2417 return true;
2418 }
2419 }
2420 }
2421 return false;
2422 }
2423
2424 private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
Amith Yamasani04e0d262012-02-14 11:50:53 -08002425 String value) {
Fred Quintana31957f12009-10-21 13:43:10 -07002426 if (account == null || key == null) {
2427 return;
2428 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002429 accounts.accountsDb.beginTransaction();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002430 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002431 long accountId = accounts.accountsDb.findDeAccountId(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002432 if (accountId < 0) {
2433 return;
2434 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002435 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002436 if (extrasId < 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002437 extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
Simranjit Kohli858511c2016-03-10 18:36:11 +00002438 if (extrasId < 0) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002439 return;
2440 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002441 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002442 return;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002443 }
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002444 writeUserDataIntoCacheLocked(accounts, account, key, value);
2445 accounts.accountsDb.setTransactionSuccessful();
Simranjit Kohli858511c2016-03-10 18:36:11 +00002446 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07002447 accounts.accountsDb.endTransaction();
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002448 }
2449 }
2450
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002451 private void onResult(IAccountManagerResponse response, Bundle result) {
Fred Quintana56285a62010-12-02 14:20:51 -08002452 if (result == null) {
2453 Log.e(TAG, "the result is unexpectedly null", new Exception());
2454 }
2455 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2456 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
2457 + response);
2458 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002459 try {
2460 response.onResult(result);
2461 } catch (RemoteException e) {
2462 // if the caller is dead then there is no one to care about remote
2463 // exceptions
2464 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2465 Log.v(TAG, "failure while notifying response", e);
2466 }
2467 }
2468 }
2469
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002470 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07002471 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
2472 final String authTokenType)
2473 throws RemoteException {
2474 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolache5f383ad92010-12-02 16:44:46 -08002475 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
2476
Fred Quintanad9640ec2012-05-23 12:37:00 -07002477 final int callingUid = getCallingUid();
2478 clearCallingIdentity();
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07002479 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07002480 throw new SecurityException("can only call from system");
2481 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002482 int userId = UserHandle.getUserId(callingUid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002483 long identityToken = clearCallingIdentity();
2484 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002485 UserAccounts accounts = getUserAccounts(userId);
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002486 new Session(accounts, response, accountType, false /* expectActivityLaunch */,
2487 false /* stripAuthTokenFromResult */, null /* accountName */,
2488 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002489 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002490 protected String toDebugString(long now) {
2491 return super.toDebugString(now) + ", getAuthTokenLabel"
Fred Quintanad9640ec2012-05-23 12:37:00 -07002492 + ", " + accountType
Costin Manolache5f383ad92010-12-02 16:44:46 -08002493 + ", authTokenType " + authTokenType;
2494 }
2495
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002496 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002497 public void run() throws RemoteException {
2498 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2499 }
2500
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002501 @Override
Costin Manolache5f383ad92010-12-02 16:44:46 -08002502 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002503 Bundle.setDefusable(result, true);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002504 if (result != null) {
2505 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
2506 Bundle bundle = new Bundle();
2507 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
2508 super.onResult(bundle);
2509 return;
2510 } else {
2511 super.onResult(result);
2512 }
2513 }
2514 }.bind();
2515 } finally {
2516 restoreCallingIdentity(identityToken);
2517 }
2518 }
2519
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002520 @Override
Carlos Valdivia91979be2015-05-22 14:11:35 -07002521 public void getAuthToken(
2522 IAccountManagerResponse response,
2523 final Account account,
2524 final String authTokenType,
2525 final boolean notifyOnAuthFailure,
2526 final boolean expectActivityLaunch,
2527 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002528 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002529 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2530 Log.v(TAG, "getAuthToken: " + account
2531 + ", response " + response
2532 + ", authTokenType " + authTokenType
2533 + ", notifyOnAuthFailure " + notifyOnAuthFailure
2534 + ", expectActivityLaunch " + expectActivityLaunch
2535 + ", caller's uid " + Binder.getCallingUid()
2536 + ", pid " + Binder.getCallingPid());
2537 }
Fred Quintana382601f2010-03-25 12:25:10 -07002538 if (response == null) throw new IllegalArgumentException("response is null");
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002539 try {
2540 if (account == null) {
2541 Slog.w(TAG, "getAuthToken called with null account");
2542 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
2543 return;
2544 }
2545 if (authTokenType == null) {
2546 Slog.w(TAG, "getAuthToken called with null authTokenType");
2547 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
2548 return;
2549 }
2550 } catch (RemoteException e) {
2551 Slog.w(TAG, "Failed to report error back to the client." + e);
2552 return;
2553 }
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002554 int userId = UserHandle.getCallingUserId();
2555 long ident = Binder.clearCallingIdentity();
2556 final UserAccounts accounts;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002557 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002558 try {
2559 accounts = getUserAccounts(userId);
2560 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
2561 AuthenticatorDescription.newKey(account.type), accounts.userId);
2562 } finally {
2563 Binder.restoreCallingIdentity(ident);
2564 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002565
Costin Manolachea40c6302010-12-13 14:50:45 -08002566 final boolean customTokens =
Carlos Valdivia91979be2015-05-22 14:11:35 -07002567 authenticatorInfo != null && authenticatorInfo.type.customTokens;
Costin Manolachea40c6302010-12-13 14:50:45 -08002568
2569 // skip the check if customTokens
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002570 final int callerUid = Binder.getCallingUid();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002571 final boolean permissionGranted =
2572 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
Costin Manolachea40c6302010-12-13 14:50:45 -08002573
Carlos Valdivia91979be2015-05-22 14:11:35 -07002574 // Get the calling package. We will use it for the purpose of caching.
2575 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
Amith Yamasanie7360012015-06-03 17:39:40 -07002576 List<String> callerOwnedPackageNames;
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002577 ident = Binder.clearCallingIdentity();
Amith Yamasanie7360012015-06-03 17:39:40 -07002578 try {
2579 callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
2580 } finally {
2581 Binder.restoreCallingIdentity(ident);
2582 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002583 if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
2584 String msg = String.format(
2585 "Uid %s is attempting to illegally masquerade as package %s!",
2586 callerUid,
2587 callerPkg);
2588 throw new SecurityException(msg);
2589 }
2590
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002591 // let authenticator know the identity of the caller
2592 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
2593 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
Carlos Valdivia91979be2015-05-22 14:11:35 -07002594
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002595 if (notifyOnAuthFailure) {
2596 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
Costin Manolachea40c6302010-12-13 14:50:45 -08002597 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002598
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002599 long identityToken = clearCallingIdentity();
2600 try {
Amith Yamasanie7360012015-06-03 17:39:40 -07002601 // Distill the caller's package signatures into a single digest.
2602 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
2603
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002604 // if the caller has permission, do the peek. otherwise go the more expensive
2605 // route of starting a Session
Costin Manolachea40c6302010-12-13 14:50:45 -08002606 if (!customTokens && permissionGranted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002607 String authToken = readAuthTokenInternal(accounts, account, authTokenType);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002608 if (authToken != null) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002609 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002610 result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
2611 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2612 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002613 onResult(response, result);
2614 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002615 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002616 }
2617
Carlos Valdivia91979be2015-05-22 14:11:35 -07002618 if (customTokens) {
2619 /*
2620 * Look up tokens in the new cache only if the loginOptions don't have parameters
2621 * outside of those expected to be injected by the AccountManager, e.g.
2622 * ANDORID_PACKAGE_NAME.
2623 */
2624 String token = readCachedTokenInternal(
2625 accounts,
2626 account,
2627 authTokenType,
2628 callerPkg,
2629 callerPkgSigDigest);
2630 if (token != null) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002631 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2632 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator.");
2633 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002634 Bundle result = new Bundle();
2635 result.putString(AccountManager.KEY_AUTHTOKEN, token);
2636 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
2637 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
2638 onResult(response, result);
2639 return;
2640 }
2641 }
2642
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002643 new Session(
2644 accounts,
2645 response,
2646 account.type,
2647 expectActivityLaunch,
2648 false /* stripAuthTokenFromResult */,
2649 account.name,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002650 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002651 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002652 protected String toDebugString(long now) {
2653 if (loginOptions != null) loginOptions.keySet();
2654 return super.toDebugString(now) + ", getAuthToken"
2655 + ", " + account
2656 + ", authTokenType " + authTokenType
2657 + ", loginOptions " + loginOptions
2658 + ", notifyOnAuthFailure " + notifyOnAuthFailure;
2659 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002660
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002661 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002662 public void run() throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002663 // If the caller doesn't have permission then create and return the
2664 // "grant permission" intent instead of the "getAuthToken" intent.
2665 if (!permissionGranted) {
2666 mAuthenticator.getAuthTokenLabel(this, authTokenType);
2667 } else {
2668 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
2669 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002670 }
2671
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002672 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002673 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002674 Bundle.setDefusable(result, true);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002675 if (result != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002676 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002677 Intent intent = newGrantCredentialsPermissionIntent(
2678 account,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002679 null,
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002680 callerUid,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002681 new AccountAuthenticatorResponse(this),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002682 authTokenType,
2683 true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002684 Bundle bundle = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002685 bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002686 onResult(bundle);
2687 return;
2688 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002689 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002690 if (authToken != null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002691 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2692 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002693 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002694 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002695 "the type and name should not be empty");
2696 return;
2697 }
Carlos Valdivia91979be2015-05-22 14:11:35 -07002698 Account resultAccount = new Account(name, type);
Costin Manolachea40c6302010-12-13 14:50:45 -08002699 if (!customTokens) {
Carlos Valdivia91979be2015-05-22 14:11:35 -07002700 saveAuthTokenToDatabase(
2701 mAccounts,
2702 resultAccount,
2703 authTokenType,
2704 authToken);
2705 }
2706 long expiryMillis = result.getLong(
2707 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
2708 if (customTokens
2709 && expiryMillis > System.currentTimeMillis()) {
2710 saveCachedToken(
2711 mAccounts,
2712 account,
2713 callerPkg,
2714 callerPkgSigDigest,
2715 authTokenType,
2716 authToken,
2717 expiryMillis);
Costin Manolachea40c6302010-12-13 14:50:45 -08002718 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002719 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002720
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002721 Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
Costin Manolached6060452011-01-24 16:11:36 -08002722 if (intent != null && notifyOnAuthFailure && !customTokens) {
Carlos Valdivia06329e5f2016-05-07 21:46:15 -07002723 /*
2724 * Make sure that the supplied intent is owned by the authenticator
2725 * giving it to the system. Otherwise a malicious authenticator could
2726 * have users launching arbitrary activities by tricking users to
2727 * interact with malicious notifications.
2728 */
2729 checkKeyIntent(
2730 Binder.getCallingUid(),
2731 intent);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08002732 doNotification(
2733 mAccounts,
2734 account,
2735 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002736 intent, "android", accounts.userId);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002737 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002738 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002739 super.onResult(result);
Fred Quintanaa698f422009-04-08 19:14:54 -07002740 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002741 }.bind();
2742 } finally {
2743 restoreCallingIdentity(identityToken);
2744 }
Fred Quintana60307342009-03-24 22:48:12 -07002745 }
2746
Carlos Valdivia91979be2015-05-22 14:11:35 -07002747 private byte[] calculatePackageSignatureDigest(String callerPkg) {
2748 MessageDigest digester;
2749 try {
2750 digester = MessageDigest.getInstance("SHA-256");
2751 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
2752 callerPkg, PackageManager.GET_SIGNATURES);
2753 for (Signature sig : pkgInfo.signatures) {
2754 digester.update(sig.toByteArray());
2755 }
2756 } catch (NoSuchAlgorithmException x) {
2757 Log.wtf(TAG, "SHA-256 should be available", x);
2758 digester = null;
2759 } catch (NameNotFoundException e) {
2760 Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
2761 digester = null;
2762 }
2763 return (digester == null) ? null : digester.digest();
2764 }
2765
Dianne Hackborn41203752012-08-31 14:05:51 -07002766 private void createNoCredentialsPermissionNotification(Account account, Intent intent,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002767 String packageName, int userId) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002768 int uid = intent.getIntExtra(
2769 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
2770 String authTokenType = intent.getStringExtra(
2771 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
Eric Fischeree452ee2009-08-31 17:58:06 -07002772 final String titleAndSubtitle =
2773 mContext.getString(R.string.permission_request_notification_with_subtitle,
2774 account.name);
2775 final int index = titleAndSubtitle.indexOf('\n');
Costin Manolache85e72792011-10-07 09:42:49 -07002776 String title = titleAndSubtitle;
2777 String subtitle = "";
2778 if (index > 0) {
2779 title = titleAndSubtitle.substring(0, index);
Maggie Benthalla12fccf2013-03-14 18:02:12 -04002780 subtitle = titleAndSubtitle.substring(index + 1);
Costin Manolache85e72792011-10-07 09:42:49 -07002781 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07002782 UserHandle user = UserHandle.of(userId);
Kenny Guy07ad8dc2014-09-01 20:56:12 +01002783 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05002784 Notification n =
2785 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
2786 .setSmallIcon(android.R.drawable.stat_sys_warning)
2787 .setWhen(0)
2788 .setColor(contextForUser.getColor(
2789 com.android.internal.R.color.system_notification_accent_color))
2790 .setContentTitle(title)
2791 .setContentText(subtitle)
2792 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
2793 PendingIntent.FLAG_CANCEL_CURRENT, null, user))
2794 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07002795 installNotification(getCredentialPermissionNotificationId(
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002796 account, authTokenType, uid), n, packageName, user.getIdentifier());
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002797 }
2798
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002799 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
2800 int uid, AccountAuthenticatorResponse response, String authTokenType,
2801 boolean startInNewTask) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002802
2803 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002804
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07002805 if (startInNewTask) {
2806 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
2807 // Since it was set in Eclair+ we can't change it without breaking apps using
2808 // the intent from a non-Activity context. This is the default behavior.
2809 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2810 }
2811 intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
2812 authTokenType, uid) + (packageName != null ? packageName : "")));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002813 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002814 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
2815 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002816 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
Costin Manolache5f383ad92010-12-02 16:44:46 -08002817
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002818 return intent;
2819 }
2820
2821 private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
2822 int uid) {
2823 Integer id;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002824 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08002825 synchronized (accounts.credentialsPermissionNotificationIds) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002826 final Pair<Pair<Account, String>, Integer> key =
2827 new Pair<Pair<Account, String>, Integer>(
2828 new Pair<Account, String>(account, authTokenType), uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002829 id = accounts.credentialsPermissionNotificationIds.get(key);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002830 if (id == null) {
2831 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002832 accounts.credentialsPermissionNotificationIds.put(key, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002833 }
2834 }
2835 return id;
2836 }
2837
Amith Yamasani04e0d262012-02-14 11:50:53 -08002838 private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002839 Integer id;
Amith Yamasani04e0d262012-02-14 11:50:53 -08002840 synchronized (accounts.signinRequiredNotificationIds) {
2841 id = accounts.signinRequiredNotificationIds.get(account);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002842 if (id == null) {
2843 id = mNotificationIds.incrementAndGet();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002844 accounts.signinRequiredNotificationIds.put(account, id);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07002845 }
2846 }
2847 return id;
2848 }
2849
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08002850 @Override
Amith Yamasani27db4682013-03-30 17:07:47 -07002851 public void addAccount(final IAccountManagerResponse response, final String accountType,
Fred Quintana33269202009-04-20 16:05:10 -07002852 final String authTokenType, final String[] requiredFeatures,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002853 final boolean expectActivityLaunch, final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002854 Bundle.setDefusable(optionsIn, true);
Fred Quintana56285a62010-12-02 14:20:51 -08002855 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2856 Log.v(TAG, "addAccount: accountType " + accountType
2857 + ", response " + response
2858 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002859 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Fred Quintana56285a62010-12-02 14:20:51 -08002860 + ", expectActivityLaunch " + expectActivityLaunch
2861 + ", caller's uid " + Binder.getCallingUid()
2862 + ", pid " + Binder.getCallingPid());
2863 }
Fred Quintana382601f2010-03-25 12:25:10 -07002864 if (response == null) throw new IllegalArgumentException("response is null");
2865 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002866
Amith Yamasani71e6c692013-03-24 17:39:28 -07002867 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002868 final int uid = Binder.getCallingUid();
2869 final int userId = UserHandle.getUserId(uid);
2870 if (!canUserModifyAccounts(userId, uid)) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002871 try {
2872 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2873 "User is not allowed to add an account!");
2874 } catch (RemoteException re) {
2875 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002876 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002877 return;
2878 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002879 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002880 try {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002881 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2882 "User cannot modify accounts of this type (policy).");
2883 } catch (RemoteException re) {
Amith Yamasani23c8b962013-04-10 13:37:18 -07002884 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002885 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2886 userId);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08002887 return;
2888 }
2889
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002890 final int pid = Binder.getCallingPid();
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07002891 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2892 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2893 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2894
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002895 int usrId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002896 long identityToken = clearCallingIdentity();
2897 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002898 UserAccounts accounts = getUserAccounts(usrId);
2899 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002900 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2901 uid);
Amith Yamasani04e0d262012-02-14 11:50:53 -08002902 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002903 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002904 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002905 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002906 public void run() throws RemoteException {
Costin Manolache3348f142009-09-29 18:58:36 -07002907 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
Fred Quintana33269202009-04-20 16:05:10 -07002908 options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002909 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002910
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07002911 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002912 protected String toDebugString(long now) {
2913 return super.toDebugString(now) + ", addAccount"
Fred Quintana33269202009-04-20 16:05:10 -07002914 + ", accountType " + accountType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002915 + ", requiredFeatures " + Arrays.toString(requiredFeatures);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07002916 }
2917 }.bind();
2918 } finally {
2919 restoreCallingIdentity(identityToken);
2920 }
Fred Quintana60307342009-03-24 22:48:12 -07002921 }
2922
Amith Yamasani2c7bc262012-11-05 16:46:02 -08002923 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002924 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
2925 final String authTokenType, final String[] requiredFeatures,
2926 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06002927 Bundle.setDefusable(optionsIn, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002928 int callingUid = Binder.getCallingUid();
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002929 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2930 Log.v(TAG, "addAccount: accountType " + accountType
2931 + ", response " + response
2932 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002933 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002934 + ", expectActivityLaunch " + expectActivityLaunch
2935 + ", caller's uid " + Binder.getCallingUid()
2936 + ", pid " + Binder.getCallingPid()
2937 + ", for user id " + userId);
2938 }
2939 if (response == null) throw new IllegalArgumentException("response is null");
2940 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002941 // Only allow the system process to add accounts of other users
Carlos Valdiviac37ee222015-06-17 20:17:37 -07002942 if (isCrossUser(callingUid, userId)) {
2943 throw new SecurityException(
2944 String.format(
2945 "User %s trying to add account for %s" ,
2946 UserHandle.getCallingUserId(),
2947 userId));
2948 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002949
2950 // Is user disallowed from modifying accounts?
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002951 if (!canUserModifyAccounts(userId, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002952 try {
2953 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
2954 "User is not allowed to add an account!");
2955 } catch (RemoteException re) {
2956 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002957 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002958 return;
2959 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00002960 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002961 try {
2962 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2963 "User cannot modify accounts of this type (policy).");
2964 } catch (RemoteException re) {
2965 }
Amith Yamasaniae7034a2014-09-22 12:42:12 -07002966 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
2967 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002968 return;
2969 }
2970
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002971 final int pid = Binder.getCallingPid();
2972 final int uid = Binder.getCallingUid();
2973 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
2974 options.putInt(AccountManager.KEY_CALLER_UID, uid);
2975 options.putInt(AccountManager.KEY_CALLER_PID, pid);
2976
2977 long identityToken = clearCallingIdentity();
2978 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07002979 UserAccounts accounts = getUserAccounts(userId);
2980 logRecordWithUid(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07002981 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
2982 userId);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002983 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08002984 true /* stripAuthTokenFromResult */, null /* accountName */,
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07002985 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002986 @Override
2987 public void run() throws RemoteException {
2988 mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
2989 options);
2990 }
2991
2992 @Override
2993 protected String toDebugString(long now) {
2994 return super.toDebugString(now) + ", addAccount"
2995 + ", accountType " + accountType
2996 + ", requiredFeatures "
2997 + (requiredFeatures != null
2998 ? TextUtils.join(",", requiredFeatures)
2999 : null);
3000 }
3001 }.bind();
3002 } finally {
3003 restoreCallingIdentity(identityToken);
3004 }
3005 }
3006
Sandra Kwan78812282015-11-04 11:19:47 -08003007 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003008 public void startAddAccountSession(
3009 final IAccountManagerResponse response,
3010 final String accountType,
3011 final String authTokenType,
3012 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -08003013 final boolean expectActivityLaunch,
3014 final Bundle optionsIn) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003015 Bundle.setDefusable(optionsIn, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003016 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3017 Log.v(TAG,
3018 "startAddAccountSession: accountType " + accountType
3019 + ", response " + response
3020 + ", authTokenType " + authTokenType
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003021 + ", requiredFeatures " + Arrays.toString(requiredFeatures)
Sandra Kwan78812282015-11-04 11:19:47 -08003022 + ", expectActivityLaunch " + expectActivityLaunch
3023 + ", caller's uid " + Binder.getCallingUid()
3024 + ", pid " + Binder.getCallingPid());
3025 }
3026 if (response == null) {
3027 throw new IllegalArgumentException("response is null");
3028 }
3029 if (accountType == null) {
3030 throw new IllegalArgumentException("accountType is null");
3031 }
3032
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003033 final int uid = Binder.getCallingUid();
3034 final int userId = UserHandle.getUserId(uid);
3035 if (!canUserModifyAccounts(userId, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003036 try {
3037 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
3038 "User is not allowed to add an account!");
3039 } catch (RemoteException re) {
3040 }
3041 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3042 return;
3043 }
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00003044 if (!canUserModifyAccountsForType(userId, accountType, uid)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003045 try {
3046 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3047 "User cannot modify accounts of this type (policy).");
3048 } catch (RemoteException re) {
3049 }
3050 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3051 userId);
3052 return;
3053 }
Sandra Kwan78812282015-11-04 11:19:47 -08003054 final int pid = Binder.getCallingPid();
Sandra Kwan78812282015-11-04 11:19:47 -08003055 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
3056 options.putInt(AccountManager.KEY_CALLER_UID, uid);
3057 options.putInt(AccountManager.KEY_CALLER_PID, pid);
3058
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003059 // Check to see if the Password should be included to the caller.
3060 String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3061 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003062 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003063
Sandra Kwan78812282015-11-04 11:19:47 -08003064 long identityToken = clearCallingIdentity();
3065 try {
Hongming Jin368aa192016-07-29 14:29:54 -07003066 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003067 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
3068 AccountsDb.TABLE_ACCOUNTS, uid);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003069 new StartAccountSession(
3070 accounts,
3071 response,
3072 accountType,
3073 expectActivityLaunch,
3074 null /* accountName */,
3075 false /* authDetailsRequired */,
3076 true /* updateLastAuthenticationTime */,
3077 isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003078 @Override
3079 public void run() throws RemoteException {
3080 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
3081 requiredFeatures, options);
3082 }
3083
3084 @Override
3085 protected String toDebugString(long now) {
3086 String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
3087 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
3088 + accountType + ", requiredFeatures "
3089 + (requiredFeatures != null ? requiredFeaturesStr : null);
3090 }
3091 }.bind();
3092 } finally {
3093 restoreCallingIdentity(identityToken);
3094 }
3095 }
3096
3097 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
3098 private abstract class StartAccountSession extends Session {
3099
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003100 private final boolean mIsPasswordForwardingAllowed;
3101
3102 public StartAccountSession(
3103 UserAccounts accounts,
3104 IAccountManagerResponse response,
3105 String accountType,
3106 boolean expectActivityLaunch,
3107 String accountName,
3108 boolean authDetailsRequired,
3109 boolean updateLastAuthenticationTime,
3110 boolean isPasswordForwardingAllowed) {
Sandra Kwan78812282015-11-04 11:19:47 -08003111 super(accounts, response, accountType, expectActivityLaunch,
3112 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
3113 updateLastAuthenticationTime);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003114 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
Sandra Kwan78812282015-11-04 11:19:47 -08003115 }
3116
3117 @Override
3118 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003119 Bundle.setDefusable(result, true);
Sandra Kwan78812282015-11-04 11:19:47 -08003120 mNumResults++;
3121 Intent intent = null;
Sandra Kwan78812282015-11-04 11:19:47 -08003122 if (result != null
3123 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08003124 checkKeyIntent(
3125 Binder.getCallingUid(),
3126 intent);
Sandra Kwan78812282015-11-04 11:19:47 -08003127 }
Sandra Kwan78812282015-11-04 11:19:47 -08003128 IAccountManagerResponse response;
3129 if (mExpectActivityLaunch && result != null
3130 && result.containsKey(AccountManager.KEY_INTENT)) {
3131 response = mResponse;
3132 } else {
3133 response = getResponseAndClose();
3134 }
3135 if (response == null) {
3136 return;
3137 }
3138 if (result == null) {
3139 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3140 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
3141 + response);
3142 }
3143 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3144 "null bundle returned");
3145 return;
3146 }
3147
3148 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
3149 // All AccountManager error codes are greater
3150 // than 0
3151 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
3152 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3153 return;
3154 }
3155
Hongming Jin368aa192016-07-29 14:29:54 -07003156 // Omit passwords if the caller isn't permitted to see them.
3157 if (!mIsPasswordForwardingAllowed) {
3158 result.remove(AccountManager.KEY_PASSWORD);
3159 }
3160
Sandra Kwan78812282015-11-04 11:19:47 -08003161 // Strip auth token from result.
3162 result.remove(AccountManager.KEY_AUTHTOKEN);
3163
3164 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3165 Log.v(TAG,
3166 getClass().getSimpleName() + " calling onResult() on response " + response);
3167 }
3168
3169 // Get the session bundle created by authenticator. The
3170 // bundle contains data necessary for finishing the session
3171 // later. The session bundle will be encrypted here and
3172 // decrypted later when trying to finish the session.
3173 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
3174 if (sessionBundle != null) {
3175 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3176 if (TextUtils.isEmpty(accountType)
Andreas Gampe9b041742015-12-11 17:23:33 -08003177 || !mAccountType.equalsIgnoreCase(accountType)) {
Sandra Kwan78812282015-11-04 11:19:47 -08003178 Log.w(TAG, "Account type in session bundle doesn't match request.");
3179 }
3180 // Add accountType info to session bundle. This will
3181 // override any value set by authenticator.
3182 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
3183
3184 // Encrypt session bundle before returning to caller.
3185 try {
3186 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3187 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
3188 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
3189 } catch (GeneralSecurityException e) {
3190 if (Log.isLoggable(TAG, Log.DEBUG)) {
3191 Log.v(TAG, "Failed to encrypt session bundle!", e);
3192 }
3193 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
3194 "failed to encrypt session bundle");
3195 return;
3196 }
3197 }
3198
3199 sendResponse(response, result);
3200 }
3201 }
3202
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003203 @Override
Sandra Kwan0b84b452016-01-20 15:25:42 -08003204 public void finishSessionAsUser(IAccountManagerResponse response,
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003205 @NonNull Bundle sessionBundle,
3206 boolean expectActivityLaunch,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003207 Bundle appInfo,
3208 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003209 Bundle.setDefusable(sessionBundle, true);
Sandra Kwan0b84b452016-01-20 15:25:42 -08003210 int callingUid = Binder.getCallingUid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003211 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3212 Log.v(TAG,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003213 "finishSession: response "+ response
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003214 + ", expectActivityLaunch " + expectActivityLaunch
Sandra Kwan0b84b452016-01-20 15:25:42 -08003215 + ", caller's uid " + callingUid
3216 + ", caller's user id " + UserHandle.getCallingUserId()
3217 + ", pid " + Binder.getCallingPid()
3218 + ", for user id " + userId);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003219 }
3220 if (response == null) {
3221 throw new IllegalArgumentException("response is null");
3222 }
3223
3224 // Session bundle is the encrypted bundle of the original bundle created by authenticator.
3225 // Account type is added to it before encryption.
3226 if (sessionBundle == null || sessionBundle.size() == 0) {
3227 throw new IllegalArgumentException("sessionBundle is empty");
3228 }
3229
Dmitry Dementyev52745472016-12-02 10:27:45 -08003230 // Only allow the system process to finish session for other users.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003231 if (isCrossUser(callingUid, userId)) {
3232 throw new SecurityException(
3233 String.format(
3234 "User %s trying to finish session for %s without cross user permission",
3235 UserHandle.getCallingUserId(),
3236 userId));
3237 }
3238
Sandra Kwan0b84b452016-01-20 15:25:42 -08003239 if (!canUserModifyAccounts(userId, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003240 sendErrorResponse(response,
3241 AccountManager.ERROR_CODE_USER_RESTRICTED,
3242 "User is not allowed to add an account!");
3243 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
3244 return;
3245 }
3246
3247 final int pid = Binder.getCallingPid();
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003248 final Bundle decryptedBundle;
3249 final String accountType;
3250 // First decrypt session bundle to get account type for checking permission.
3251 try {
3252 CryptoHelper cryptoHelper = CryptoHelper.getInstance();
3253 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle);
3254 if (decryptedBundle == null) {
3255 sendErrorResponse(
3256 response,
3257 AccountManager.ERROR_CODE_BAD_REQUEST,
3258 "failed to decrypt session bundle");
3259 return;
3260 }
3261 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
3262 // Account type cannot be null. This should not happen if session bundle was created
3263 // properly by #StartAccountSession.
3264 if (TextUtils.isEmpty(accountType)) {
3265 sendErrorResponse(
3266 response,
3267 AccountManager.ERROR_CODE_BAD_ARGUMENTS,
3268 "accountType is empty");
3269 return;
3270 }
3271
3272 // If by any chances, decryptedBundle contains colliding keys with
3273 // system info
3274 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or
3275 // update credentials flow, we should replace with the new values of the current call.
3276 if (appInfo != null) {
3277 decryptedBundle.putAll(appInfo);
3278 }
3279
3280 // Add info that may be used by add account or update credentials flow.
Sandra Kwan0b84b452016-01-20 15:25:42 -08003281 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003282 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
3283 } catch (GeneralSecurityException e) {
3284 if (Log.isLoggable(TAG, Log.DEBUG)) {
3285 Log.v(TAG, "Failed to decrypt session bundle!", e);
3286 }
3287 sendErrorResponse(
3288 response,
3289 AccountManager.ERROR_CODE_BAD_REQUEST,
3290 "failed to decrypt session bundle");
3291 return;
3292 }
3293
Sandra Kwan0b84b452016-01-20 15:25:42 -08003294 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003295 sendErrorResponse(
3296 response,
3297 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3298 "User cannot modify accounts of this type (policy).");
3299 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
3300 userId);
3301 return;
3302 }
3303
3304 long identityToken = clearCallingIdentity();
3305 try {
3306 UserAccounts accounts = getUserAccounts(userId);
3307 logRecordWithUid(
3308 accounts,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07003309 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
3310 AccountsDb.TABLE_ACCOUNTS,
Sandra Kwan0b84b452016-01-20 15:25:42 -08003311 callingUid);
Sandra Kwan920f6ef2015-11-10 14:13:29 -08003312 new Session(
3313 accounts,
3314 response,
3315 accountType,
3316 expectActivityLaunch,
3317 true /* stripAuthTokenFromResult */,
3318 null /* accountName */,
3319 false /* authDetailsRequired */,
3320 true /* updateLastAuthenticationTime */) {
3321 @Override
3322 public void run() throws RemoteException {
3323 mAuthenticator.finishSession(this, mAccountType, decryptedBundle);
3324 }
3325
3326 @Override
3327 protected String toDebugString(long now) {
3328 return super.toDebugString(now)
3329 + ", finishSession"
3330 + ", accountType " + accountType;
3331 }
3332 }.bind();
3333 } finally {
3334 restoreCallingIdentity(identityToken);
3335 }
3336 }
3337
Amith Yamasaniae7034a2014-09-22 12:42:12 -07003338 private void showCantAddAccount(int errorCode, int userId) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003339 final DevicePolicyManagerInternal dpmi =
3340 LocalServices.getService(DevicePolicyManagerInternal.class);
3341 Intent intent = null;
Nicolas Prevot14fc1972016-08-24 14:21:38 +01003342 if (dpmi == null) {
3343 intent = getDefaultCantAddAccountIntent(errorCode);
3344 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003345 intent = dpmi.createUserRestrictionSupportIntent(userId,
3346 UserManager.DISALLOW_MODIFY_ACCOUNTS);
3347 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
3348 intent = dpmi.createShowAdminSupportIntent(userId, false);
3349 }
3350 if (intent == null) {
3351 intent = getDefaultCantAddAccountIntent(errorCode);
3352 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003353 long identityToken = clearCallingIdentity();
3354 try {
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003355 mContext.startActivityAsUser(intent, new UserHandle(userId));
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003356 } finally {
3357 restoreCallingIdentity(identityToken);
3358 }
3359 }
3360
Nicolas Prevot709a63d2016-06-09 13:14:00 +01003361 /**
3362 * Called when we don't know precisely who is preventing us from adding an account.
3363 */
3364 private Intent getDefaultCantAddAccountIntent(int errorCode) {
3365 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
3366 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
3367 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3368 return cantAddAccount;
3369 }
3370
Alexandra Gherghina999d3942014-07-03 11:40:08 +01003371 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003372 public void confirmCredentialsAsUser(
3373 IAccountManagerResponse response,
3374 final Account account,
3375 final Bundle options,
3376 final boolean expectActivityLaunch,
Amith Yamasani2c7bc262012-11-05 16:46:02 -08003377 int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003378 Bundle.setDefusable(options, true);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003379 int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003380 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3381 Log.v(TAG, "confirmCredentials: " + account
3382 + ", response " + response
3383 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003384 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003385 + ", pid " + Binder.getCallingPid());
3386 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003387 // Only allow the system process to read accounts of other users
3388 if (isCrossUser(callingUid, userId)) {
3389 throw new SecurityException(
3390 String.format(
3391 "User %s trying to confirm account credentials for %s" ,
3392 UserHandle.getCallingUserId(),
3393 userId));
3394 }
Fred Quintana382601f2010-03-25 12:25:10 -07003395 if (response == null) throw new IllegalArgumentException("response is null");
3396 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003397 long identityToken = clearCallingIdentity();
3398 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003399 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003400 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003401 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003402 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003403 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003404 public void run() throws RemoteException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003405 mAuthenticator.confirmCredentials(this, account, options);
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003406 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003407 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003408 protected String toDebugString(long now) {
3409 return super.toDebugString(now) + ", confirmCredentials"
3410 + ", " + account;
3411 }
3412 }.bind();
3413 } finally {
3414 restoreCallingIdentity(identityToken);
3415 }
Fred Quintana60307342009-03-24 22:48:12 -07003416 }
3417
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003418 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003419 public void updateCredentials(IAccountManagerResponse response, final Account account,
3420 final String authTokenType, final boolean expectActivityLaunch,
3421 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003422 Bundle.setDefusable(loginOptions, true);
Fred Quintana56285a62010-12-02 14:20:51 -08003423 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3424 Log.v(TAG, "updateCredentials: " + account
3425 + ", response " + response
3426 + ", authTokenType " + authTokenType
3427 + ", expectActivityLaunch " + expectActivityLaunch
3428 + ", caller's uid " + Binder.getCallingUid()
3429 + ", pid " + Binder.getCallingPid());
3430 }
Fred Quintana382601f2010-03-25 12:25:10 -07003431 if (response == null) throw new IllegalArgumentException("response is null");
3432 if (account == null) throw new IllegalArgumentException("account is null");
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003433 int userId = UserHandle.getCallingUserId();
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003434 long identityToken = clearCallingIdentity();
3435 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003436 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003437 new Session(accounts, response, account.type, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003438 true /* stripAuthTokenFromResult */, account.name,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07003439 false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003440 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003441 public void run() throws RemoteException {
3442 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
3443 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003444 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003445 protected String toDebugString(long now) {
3446 if (loginOptions != null) loginOptions.keySet();
3447 return super.toDebugString(now) + ", updateCredentials"
3448 + ", " + account
3449 + ", authTokenType " + authTokenType
3450 + ", loginOptions " + loginOptions;
3451 }
3452 }.bind();
3453 } finally {
3454 restoreCallingIdentity(identityToken);
3455 }
Fred Quintana60307342009-03-24 22:48:12 -07003456 }
3457
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003458 @Override
Sandra Kwane68c37e2015-11-12 17:11:49 -08003459 public void startUpdateCredentialsSession(
3460 IAccountManagerResponse response,
3461 final Account account,
3462 final String authTokenType,
3463 final boolean expectActivityLaunch,
3464 final Bundle loginOptions) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003465 Bundle.setDefusable(loginOptions, true);
Sandra Kwane68c37e2015-11-12 17:11:49 -08003466 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3467 Log.v(TAG,
3468 "startUpdateCredentialsSession: " + account + ", response " + response
3469 + ", authTokenType " + authTokenType + ", expectActivityLaunch "
3470 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid()
3471 + ", pid " + Binder.getCallingPid());
3472 }
3473 if (response == null) {
3474 throw new IllegalArgumentException("response is null");
3475 }
3476 if (account == null) {
3477 throw new IllegalArgumentException("account is null");
3478 }
Sandra Kwana578d112015-12-16 16:01:43 -08003479
3480 final int uid = Binder.getCallingUid();
Sandra Kwane68c37e2015-11-12 17:11:49 -08003481 int userId = UserHandle.getCallingUserId();
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003482
3483 // Check to see if the Password should be included to the caller.
3484 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
3485 boolean isPasswordForwardingAllowed = isPermitted(
Carlos Valdivia714bbd82016-04-22 14:10:40 -07003486 callerPkg, uid, Manifest.permission.GET_PASSWORD);
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003487
Sandra Kwane68c37e2015-11-12 17:11:49 -08003488 long identityToken = clearCallingIdentity();
3489 try {
3490 UserAccounts accounts = getUserAccounts(userId);
3491 new StartAccountSession(
3492 accounts,
3493 response,
3494 account.type,
3495 expectActivityLaunch,
3496 account.name,
3497 false /* authDetailsRequired */,
Carlos Valdivia51b651a2016-03-30 13:44:28 -07003498 true /* updateLastCredentialTime */,
3499 isPasswordForwardingAllowed) {
Sandra Kwane68c37e2015-11-12 17:11:49 -08003500 @Override
3501 public void run() throws RemoteException {
3502 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
3503 loginOptions);
3504 }
3505
3506 @Override
3507 protected String toDebugString(long now) {
3508 if (loginOptions != null)
3509 loginOptions.keySet();
3510 return super.toDebugString(now)
3511 + ", startUpdateCredentialsSession"
3512 + ", " + account
3513 + ", authTokenType " + authTokenType
3514 + ", loginOptions " + loginOptions;
3515 }
3516 }.bind();
3517 } finally {
3518 restoreCallingIdentity(identityToken);
3519 }
3520 }
3521
3522 @Override
Sandra Kwan390c9d22016-01-12 14:13:37 -08003523 public void isCredentialsUpdateSuggested(
3524 IAccountManagerResponse response,
3525 final Account account,
3526 final String statusToken) {
3527 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3528 Log.v(TAG,
3529 "isCredentialsUpdateSuggested: " + account + ", response " + response
3530 + ", caller's uid " + Binder.getCallingUid()
3531 + ", pid " + Binder.getCallingPid());
3532 }
3533 if (response == null) {
3534 throw new IllegalArgumentException("response is null");
3535 }
3536 if (account == null) {
3537 throw new IllegalArgumentException("account is null");
3538 }
3539 if (TextUtils.isEmpty(statusToken)) {
3540 throw new IllegalArgumentException("status token is empty");
3541 }
3542
Sandra Kwan390c9d22016-01-12 14:13:37 -08003543 int usrId = UserHandle.getCallingUserId();
3544 long identityToken = clearCallingIdentity();
3545 try {
3546 UserAccounts accounts = getUserAccounts(usrId);
3547 new Session(accounts, response, account.type, false /* expectActivityLaunch */,
3548 false /* stripAuthTokenFromResult */, account.name,
3549 false /* authDetailsRequired */) {
3550 @Override
3551 protected String toDebugString(long now) {
3552 return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
3553 + ", " + account;
3554 }
3555
3556 @Override
3557 public void run() throws RemoteException {
3558 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
3559 }
3560
3561 @Override
3562 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003563 Bundle.setDefusable(result, true);
Sandra Kwan390c9d22016-01-12 14:13:37 -08003564 IAccountManagerResponse response = getResponseAndClose();
3565 if (response == null) {
3566 return;
3567 }
3568
3569 if (result == null) {
3570 sendErrorResponse(
3571 response,
3572 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3573 "null bundle");
3574 return;
3575 }
3576
3577 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3578 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3579 + response);
3580 }
3581 // Check to see if an error occurred. We know if an error occurred because all
3582 // error codes are greater than 0.
3583 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
3584 sendErrorResponse(response,
3585 result.getInt(AccountManager.KEY_ERROR_CODE),
3586 result.getString(AccountManager.KEY_ERROR_MESSAGE));
3587 return;
3588 }
3589 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
3590 sendErrorResponse(
3591 response,
3592 AccountManager.ERROR_CODE_INVALID_RESPONSE,
3593 "no result in response");
3594 return;
3595 }
3596 final Bundle newResult = new Bundle();
3597 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
3598 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
3599 sendResponse(response, newResult);
3600 }
3601 }.bind();
3602 } finally {
3603 restoreCallingIdentity(identityToken);
3604 }
3605 }
3606
3607 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07003608 public void editProperties(IAccountManagerResponse response, final String accountType,
3609 final boolean expectActivityLaunch) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003610 final int callingUid = Binder.getCallingUid();
Fred Quintana56285a62010-12-02 14:20:51 -08003611 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3612 Log.v(TAG, "editProperties: accountType " + accountType
3613 + ", response " + response
3614 + ", expectActivityLaunch " + expectActivityLaunch
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003615 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08003616 + ", pid " + Binder.getCallingPid());
3617 }
Fred Quintana382601f2010-03-25 12:25:10 -07003618 if (response == null) throw new IllegalArgumentException("response is null");
3619 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003620 int userId = UserHandle.getCallingUserId();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003621 if (!isAccountManagedByCaller(accountType, callingUid, userId)
3622 && !isSystemUid(callingUid)) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07003623 String msg = String.format(
3624 "uid %s cannot edit authenticator properites for account type: %s",
3625 callingUid,
3626 accountType);
3627 throw new SecurityException(msg);
3628 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003629 long identityToken = clearCallingIdentity();
3630 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07003631 UserAccounts accounts = getUserAccounts(userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003632 new Session(accounts, response, accountType, expectActivityLaunch,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003633 true /* stripAuthTokenFromResult */, null /* accountName */,
3634 false /* authDetailsRequired */) {
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003635 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003636 public void run() throws RemoteException {
3637 mAuthenticator.editProperties(this, mAccountType);
3638 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003639 @Override
Fred Quintana26fc5eb2009-04-09 15:05:50 -07003640 protected String toDebugString(long now) {
3641 return super.toDebugString(now) + ", editProperties"
3642 + ", accountType " + accountType;
3643 }
3644 }.bind();
3645 } finally {
3646 restoreCallingIdentity(identityToken);
3647 }
Fred Quintana60307342009-03-24 22:48:12 -07003648 }
3649
Amith Yamasani12747872015-12-07 14:19:49 -08003650 @Override
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003651 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3652 @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003653 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003654 throw new SecurityException("Can be called only by system UID");
3655 }
3656 Preconditions.checkNotNull(account, "account cannot be null");
3657 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3658 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3659
3660 final int userId = userHandle.getIdentifier();
3661
3662 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3663
3664 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003665 int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
Svet Ganovf6d424f12016-09-20 20:18:53 -07003666 return hasAccountAccess(account, packageName, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003667 } catch (NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003668 Log.d(TAG, "Package not found " + e.getMessage());
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003669 return false;
3670 }
3671 }
3672
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003673 // Returns package with oldest target SDK for given UID.
3674 private String getPackageNameForUid(int uid) {
3675 String[] packageNames = mPackageManager.getPackagesForUid(uid);
3676 if (ArrayUtils.isEmpty(packageNames)) {
3677 return null;
3678 }
3679 // For app op checks related to permissions all packages in the UID
3680 // have the same app op state, so doesn't matter which one we pick.
3681 // Update: due to visibility changes we want to use package with oldest target SDK,
3682
3683 String packageName = packageNames[0];
3684 int oldestVersion = Integer.MAX_VALUE;
3685 for (String name : packageNames) {
3686 try {
3687 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
3688 if (applicationInfo != null) {
3689 int version = applicationInfo.targetSdkVersion;
3690 if (version < oldestVersion) {
3691 oldestVersion = version;
3692 packageName = name;
3693 }
3694 }
3695 } catch (NameNotFoundException e) {
3696 // skip
3697 }
3698 }
3699 return packageName;
3700 }
3701
Svet Ganovf6d424f12016-09-20 20:18:53 -07003702 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
3703 int uid) {
3704 if (packageName == null) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003705 packageName = getPackageNameForUid(uid);
3706 if (packageName == null) {
Svet Ganovf6d424f12016-09-20 20:18:53 -07003707 return false;
3708 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003709 }
3710
3711 // Use null token which means any token. Having a token means the package
3712 // is trusted by the authenticator, hence it is fine to access the account.
3713 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
3714 return true;
3715 }
3716 // In addition to the permissions required to get an auth token we also allow
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003717 // the account to be accessed by apps for which user or authenticator granted visibility.
Svet Ganovf6d424f12016-09-20 20:18:53 -07003718
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003719 int visibility = resolveAccountVisibility(account, packageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003720 getUserAccounts(UserHandle.getUserId(uid)));
3721 return (visibility == AccountManager.VISIBILITY_VISIBLE
3722 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003723 }
3724
3725 @Override
3726 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3727 @NonNull String packageName, @NonNull UserHandle userHandle) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003728 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003729 throw new SecurityException("Can be called only by system UID");
3730 }
3731
3732 Preconditions.checkNotNull(account, "account cannot be null");
3733 Preconditions.checkNotNull(packageName, "packageName cannot be null");
3734 Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
3735
3736 final int userId = userHandle.getIdentifier();
3737
3738 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
3739
3740 final int uid;
3741 try {
3742 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
3743 } catch (NameNotFoundException e) {
3744 Slog.e(TAG, "Unknown package " + packageName);
3745 return null;
3746 }
3747
3748 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
3749
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07003750 final long identity = Binder.clearCallingIdentity();
3751 try {
3752 return PendingIntent.getActivityAsUser(
3753 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
3754 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3755 null, new UserHandle(userId)).getIntentSender();
3756 } finally {
3757 Binder.restoreCallingIdentity(identity);
3758 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003759 }
3760
3761 private Intent newRequestAccountAccessIntent(Account account, String packageName,
3762 int uid, RemoteCallback callback) {
3763 return newGrantCredentialsPermissionIntent(account, packageName, uid,
3764 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
3765 @Override
3766 public void onResult(Bundle value) throws RemoteException {
3767 handleAuthenticatorResponse(true);
3768 }
3769
3770 @Override
3771 public void onRequestContinued() {
3772 /* ignore */
3773 }
3774
3775 @Override
3776 public void onError(int errorCode, String errorMessage) throws RemoteException {
3777 handleAuthenticatorResponse(false);
3778 }
3779
3780 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
3781 cancelNotification(getCredentialPermissionNotificationId(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003782 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003783 UserHandle.getUserHandleForUid(uid));
3784 if (callback != null) {
3785 Bundle result = new Bundle();
3786 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
3787 callback.sendResult(result);
3788 }
3789 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07003790 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003791 }
3792
3793 @Override
Amith Yamasani12747872015-12-07 14:19:49 -08003794 public boolean someUserHasAccount(@NonNull final Account account) {
3795 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
3796 throw new SecurityException("Only system can check for accounts across users");
3797 }
3798 final long token = Binder.clearCallingIdentity();
3799 try {
3800 AccountAndUser[] allAccounts = getAllAccounts();
3801 for (int i = allAccounts.length - 1; i >= 0; i--) {
3802 if (allAccounts[i].account.equals(account)) {
3803 return true;
3804 }
3805 }
3806 return false;
3807 } finally {
3808 Binder.restoreCallingIdentity(token);
3809 }
3810 }
3811
Fred Quintana33269202009-04-20 16:05:10 -07003812 private class GetAccountsByTypeAndFeatureSession extends Session {
3813 private final String[] mFeatures;
3814 private volatile Account[] mAccountsOfType = null;
3815 private volatile ArrayList<Account> mAccountsWithFeatures = null;
3816 private volatile int mCurrentAccount = 0;
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08003817 private final int mCallingUid;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003818 private final String mPackageName;
Fred Quintana33269202009-04-20 16:05:10 -07003819
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003820 public GetAccountsByTypeAndFeatureSession(
3821 UserAccounts accounts,
3822 IAccountManagerResponse response,
3823 String type,
3824 String[] features,
3825 int callingUid,
3826 String packageName) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003827 super(accounts, response, type, false /* expectActivityLaunch */,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08003828 true /* stripAuthTokenFromResult */, null /* accountName */,
3829 false /* authDetailsRequired */);
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003830 mCallingUid = callingUid;
Fred Quintana33269202009-04-20 16:05:10 -07003831 mFeatures = features;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003832 mPackageName = packageName;
Fred Quintana33269202009-04-20 16:05:10 -07003833 }
3834
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003835 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003836 public void run() throws RemoteException {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003837 synchronized (mAccounts.cacheLock) {
Amith Yamasani27db4682013-03-30 17:07:47 -07003838 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003839 mPackageName, false /* include managed not visible*/);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08003840 }
Fred Quintana33269202009-04-20 16:05:10 -07003841 // check whether each account matches the requested features
Tejas Khorana5edff3b2016-06-28 20:59:52 -07003842 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
Fred Quintana33269202009-04-20 16:05:10 -07003843 mCurrentAccount = 0;
3844
3845 checkAccount();
3846 }
3847
3848 public void checkAccount() {
3849 if (mCurrentAccount >= mAccountsOfType.length) {
3850 sendResult();
3851 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07003852 }
Fred Quintana33269202009-04-20 16:05:10 -07003853
Fred Quintana29e94b82010-03-10 12:11:51 -08003854 final IAccountAuthenticator accountAuthenticator = mAuthenticator;
3855 if (accountAuthenticator == null) {
3856 // It is possible that the authenticator has died, which is indicated by
3857 // mAuthenticator being set to null. If this happens then just abort.
3858 // There is no need to send back a result or error in this case since
3859 // that already happened when mAuthenticator was cleared.
3860 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3861 Log.v(TAG, "checkAccount: aborting session since we are no longer"
3862 + " connected to the authenticator, " + toDebugString());
3863 }
3864 return;
3865 }
Fred Quintana33269202009-04-20 16:05:10 -07003866 try {
Fred Quintana29e94b82010-03-10 12:11:51 -08003867 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
Fred Quintana33269202009-04-20 16:05:10 -07003868 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003869 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
Fred Quintana33269202009-04-20 16:05:10 -07003870 }
3871 }
3872
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003873 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003874 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06003875 Bundle.setDefusable(result, true);
Fred Quintana33269202009-04-20 16:05:10 -07003876 mNumResults++;
3877 if (result == null) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003878 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
Fred Quintana33269202009-04-20 16:05:10 -07003879 return;
3880 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003881 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
Fred Quintana33269202009-04-20 16:05:10 -07003882 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
3883 }
3884 mCurrentAccount++;
3885 checkAccount();
3886 }
3887
3888 public void sendResult() {
3889 IAccountManagerResponse response = getResponseAndClose();
3890 if (response != null) {
3891 try {
3892 Account[] accounts = new Account[mAccountsWithFeatures.size()];
3893 for (int i = 0; i < accounts.length; i++) {
3894 accounts[i] = mAccountsWithFeatures.get(i);
3895 }
Fred Quintana56285a62010-12-02 14:20:51 -08003896 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3897 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
3898 + response);
3899 }
Fred Quintana33269202009-04-20 16:05:10 -07003900 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07003901 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
Fred Quintana33269202009-04-20 16:05:10 -07003902 response.onResult(result);
3903 } catch (RemoteException e) {
3904 // if the caller is dead then there is no one to care about remote exceptions
3905 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3906 Log.v(TAG, "failure while notifying response", e);
3907 }
3908 }
3909 }
3910 }
3911
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07003912 @Override
Fred Quintana33269202009-04-20 16:05:10 -07003913 protected String toDebugString(long now) {
3914 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
3915 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
3916 }
3917 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07003918
Amith Yamasani04e0d262012-02-14 11:50:53 -08003919 /**
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003920 * Returns the accounts visible to the client within the context of a specific user
Amith Yamasani04e0d262012-02-14 11:50:53 -08003921 * @hide
3922 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003923 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07003924 public Account[] getAccounts(int userId, String opPackageName) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08003925 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003926 mAppOpsManager.checkPackage(callingUid, opPackageName);
Svetoslavf3f02ac2015-09-08 14:36:35 -07003927 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
3928 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003929 if (visibleAccountTypes.isEmpty()) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08003930 return EMPTY_ACCOUNT_ARRAY;
Carlos Valdiviac37ee222015-06-17 20:17:37 -07003931 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08003932 long identityToken = clearCallingIdentity();
3933 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003934 UserAccounts accounts = getUserAccounts(userId);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003935 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07003936 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00003937 callingUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003938 opPackageName,
3939 visibleAccountTypes,
3940 false /* includeUserManagedNotVisible */);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003941 } finally {
3942 restoreCallingIdentity(identityToken);
3943 }
3944 }
3945
Amith Yamasanif29f2362012-04-05 18:29:52 -07003946 /**
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003947 * Returns accounts for all running users, ignores visibility values.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003948 *
Amith Yamasanif29f2362012-04-05 18:29:52 -07003949 * @hide
3950 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003951 @NonNull
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003952 public AccountAndUser[] getRunningAccounts() {
3953 final int[] runningUserIds;
3954 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08003955 runningUserIds = ActivityManager.getService().getRunningUserIds();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003956 } catch (RemoteException e) {
3957 // Running in system_server; should never happen
3958 throw new RuntimeException(e);
3959 }
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003960 return getAccounts(runningUserIds);
3961 }
Amith Yamasanif29f2362012-04-05 18:29:52 -07003962
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003963 /**
3964 * Returns accounts for all users, ignores visibility values.
3965 *
3966 * @hide
3967 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003968 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003969 public AccountAndUser[] getAllAccounts() {
Amith Yamasanid04aaa32016-06-13 12:09:36 -07003970 final List<UserInfo> users = getUserManager().getUsers(true);
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003971 final int[] userIds = new int[users.size()];
3972 for (int i = 0; i < userIds.length; i++) {
3973 userIds[i] = users.get(i).id;
3974 }
3975 return getAccounts(userIds);
3976 }
3977
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003978 @NonNull
Jeff Sharkey6eb96202012-10-10 13:13:54 -07003979 private AccountAndUser[] getAccounts(int[] userIds) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003980 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
Amith Yamasani0c19bf52013-10-03 10:34:58 -07003981 for (int userId : userIds) {
3982 UserAccounts userAccounts = getUserAccounts(userId);
3983 if (userAccounts == null) continue;
3984 synchronized (userAccounts.cacheLock) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003985 Account[] accounts = getAccountsFromCacheLocked(
3986 userAccounts,
3987 null /* type */,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08003988 Binder.getCallingUid(),
Dmitry Dementyeve366f822017-01-31 10:25:10 -08003989 null /* packageName */,
3990 false /* include managed not visible*/);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07003991 for (int a = 0; a < accounts.length; a++) {
3992 runningAccounts.add(new AccountAndUser(accounts[a], userId));
Amith Yamasanif29f2362012-04-05 18:29:52 -07003993 }
3994 }
3995 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07003996
3997 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
3998 return runningAccounts.toArray(accountsArray);
Amith Yamasanif29f2362012-04-05 18:29:52 -07003999 }
4000
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004001 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004002 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004003 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004004 int callingUid = Binder.getCallingUid();
4005 mAppOpsManager.checkPackage(callingUid, opPackageName);
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004006 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004007 opPackageName, false /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004008 }
4009
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004010 @NonNull
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004011 private Account[] getAccountsAsUserForPackage(
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004012 String type,
4013 int userId,
4014 String callingPackage,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004015 int packageUid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004016 String opPackageName,
4017 boolean includeUserManagedNotVisible) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004018 int callingUid = Binder.getCallingUid();
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004019 // Only allow the system process to read accounts of other users
4020 if (userId != UserHandle.getCallingUserId()
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004021 && callingUid != Process.SYSTEM_UID
Jim Miller464f5302013-02-27 18:33:25 -08004022 && mContext.checkCallingOrSelfPermission(
4023 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
4024 != PackageManager.PERMISSION_GRANTED) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004025 throw new SecurityException("User " + UserHandle.getCallingUserId()
4026 + " trying to get account for " + userId);
4027 }
4028
Fred Quintana56285a62010-12-02 14:20:51 -08004029 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4030 Log.v(TAG, "getAccounts: accountType " + type
4031 + ", caller's uid " + Binder.getCallingUid()
4032 + ", pid " + Binder.getCallingPid());
4033 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004034
4035 // If the original calling app was using account choosing activity
4036 // provided by the framework or authenticator we'll passing in
4037 // the original caller's uid here, which is what should be used for filtering.
4038 List<String> managedTypes =
4039 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
4040 if (packageUid != -1 &&
4041 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
4042 || (type != null && managedTypes.contains(type))))) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004043 callingUid = packageUid;
Svetoslav5579e412015-09-10 15:30:45 -07004044 opPackageName = callingPackage;
Amith Yamasani27db4682013-03-30 17:07:47 -07004045 }
Svetoslavf3f02ac2015-09-08 14:36:35 -07004046 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4047 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004048 if (visibleAccountTypes.isEmpty()
4049 || (type != null && !visibleAccountTypes.contains(type))) {
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004050 return EMPTY_ACCOUNT_ARRAY;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004051 } else if (visibleAccountTypes.contains(type)) {
4052 // Prune the list down to just the requested type.
4053 visibleAccountTypes = new ArrayList<>();
4054 visibleAccountTypes.add(type);
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07004055 } // else aggregate all the visible accounts (it won't matter if the
4056 // list is empty).
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004057
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004058 long identityToken = clearCallingIdentity();
4059 try {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004060 UserAccounts accounts = getUserAccounts(userId);
Dmitry Dementyev52745472016-12-02 10:27:45 -08004061 return getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004062 accounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004063 callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004064 opPackageName,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004065 visibleAccountTypes,
4066 includeUserManagedNotVisible);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004067 } finally {
4068 restoreCallingIdentity(identityToken);
4069 }
4070 }
4071
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004072 @NonNull
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004073 private Account[] getAccountsInternal(
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004074 UserAccounts userAccounts,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004075 int callingUid,
4076 String callingPackage,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004077 List<String> visibleAccountTypes,
4078 boolean includeUserManagedNotVisible) {
Carlos Valdiviaa3721e12015-08-10 18:40:06 -07004079 synchronized (userAccounts.cacheLock) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004080 ArrayList<Account> visibleAccounts = new ArrayList<>();
4081 for (String visibleType : visibleAccountTypes) {
4082 Account[] accountsForType = getAccountsFromCacheLocked(
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004083 userAccounts, visibleType, callingUid, callingPackage,
4084 includeUserManagedNotVisible);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004085 if (accountsForType != null) {
4086 visibleAccounts.addAll(Arrays.asList(accountsForType));
4087 }
4088 }
4089 Account[] result = new Account[visibleAccounts.size()];
4090 for (int i = 0; i < visibleAccounts.size(); i++) {
4091 result[i] = visibleAccounts.get(i);
4092 }
4093 return result;
4094 }
4095 }
4096
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004097 @Override
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004098 public void addSharedAccountsFromParentUser(int parentUserId, int userId,
4099 String opPackageName) {
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07004100 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
Sudheer Shankaf88ebeb2017-02-14 18:30:40 -08004101 Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004102 for (Account account : accounts) {
4103 addSharedAccountAsUser(account, userId);
4104 }
4105 }
4106
4107 private boolean addSharedAccountAsUser(Account account, int userId) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004108 userId = handleIncomingUser(userId);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004109 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004110 accounts.accountsDb.deleteSharedAccount(account);
4111 long accountId = accounts.accountsDb.insertSharedAccount(account);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004112 if (accountId < 0) {
4113 Log.w(TAG, "insertAccountIntoDatabase: " + account
4114 + ", skipping the DB insert failed");
4115 return false;
4116 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004117 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
4118 accounts);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004119 return true;
4120 }
4121
4122 @Override
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004123 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
4124 userId = handleIncomingUser(userId);
4125 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004126 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4127 int r = accounts.accountsDb.renameSharedAccount(account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004128 if (r > 0) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004129 int callingUid = getCallingUid();
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004130 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004131 sharedTableAccountId, accounts, callingUid);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004132 // Recursively rename the account.
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004133 renameAccountInternal(accounts, account, newName);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07004134 }
4135 return r > 0;
4136 }
4137
4138 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -08004139 public boolean removeSharedAccountAsUser(Account account, int userId) {
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004140 return removeSharedAccountAsUser(account, userId, getCallingUid());
4141 }
4142
4143 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08004144 userId = handleIncomingUser(userId);
4145 UserAccounts accounts = getUserAccounts(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004146 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
4147 boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004148 if (deleted) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004149 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004150 sharedTableAccountId, accounts, callingUid);
Fyodor Kupolov06a484a2015-08-21 16:33:20 -07004151 removeAccountInternal(accounts, account, callingUid);
Amith Yamasani67df64b2012-12-14 12:09:36 -08004152 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07004153 return deleted;
Amith Yamasani67df64b2012-12-14 12:09:36 -08004154 }
4155
4156 @Override
4157 public Account[] getSharedAccountsAsUser(int userId) {
4158 userId = handleIncomingUser(userId);
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004159 UserAccounts accounts = getUserAccounts(userId);
4160 List<Account> accountList = accounts.accountsDb.getSharedAccounts();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004161 Account[] accountArray = new Account[accountList.size()];
4162 accountList.toArray(accountArray);
4163 return accountArray;
4164 }
4165
4166 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004167 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004168 public Account[] getAccounts(String type, String opPackageName) {
Tejas Khorana69990d92016-08-03 11:19:40 -07004169 return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
Amith Yamasani2c7bc262012-11-05 16:46:02 -08004170 }
4171
Amith Yamasani27db4682013-03-30 17:07:47 -07004172 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004173 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004174 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
Amith Yamasani27db4682013-03-30 17:07:47 -07004175 int callingUid = Binder.getCallingUid();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004176 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004177 // Don't do opPackageName check - caller is system.
Amith Yamasani27db4682013-03-30 17:07:47 -07004178 throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
4179 + callingUid + " with uid=" + uid);
4180 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004181 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004182 opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani27db4682013-03-30 17:07:47 -07004183 }
4184
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004185 @Override
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07004186 @NonNull
Svetoslavf3f02ac2015-09-08 14:36:35 -07004187 public Account[] getAccountsByTypeForPackage(String type, String packageName,
4188 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004189 int callingUid = Binder.getCallingUid();
4190 int userId = UserHandle.getCallingUserId();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004191 mAppOpsManager.checkPackage(callingUid, opPackageName);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004192 int packageUid = -1;
4193 try {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004194 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
4195 } catch (NameNotFoundException re) {
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004196 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004197 return EMPTY_ACCOUNT_ARRAY;
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004198 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004199 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004200 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
4201 return EMPTY_ACCOUNT_ARRAY;
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004202 }
Dmitry Dementyev5159f432017-03-09 12:59:56 -08004203 return getAccountsAsUserForPackage(type, userId,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004204 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
Amith Yamasani3b458ad2013-04-18 18:40:07 -07004205 }
4206
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004207 @Override
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004208 public void getAccountsByFeatures(
4209 IAccountManagerResponse response,
4210 String type,
Svetoslavf3f02ac2015-09-08 14:36:35 -07004211 String[] features,
4212 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004213 int callingUid = Binder.getCallingUid();
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004214 mAppOpsManager.checkPackage(callingUid, opPackageName);
Fred Quintana56285a62010-12-02 14:20:51 -08004215 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4216 Log.v(TAG, "getAccounts: accountType " + type
4217 + ", response " + response
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004218 + ", features " + Arrays.toString(features)
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004219 + ", caller's uid " + callingUid
Fred Quintana56285a62010-12-02 14:20:51 -08004220 + ", pid " + Binder.getCallingPid());
4221 }
Fred Quintana382601f2010-03-25 12:25:10 -07004222 if (response == null) throw new IllegalArgumentException("response is null");
4223 if (type == null) throw new IllegalArgumentException("accountType is null");
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004224 int userId = UserHandle.getCallingUserId();
4225
Svetoslavf3f02ac2015-09-08 14:36:35 -07004226 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
4227 opPackageName);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004228 if (!visibleAccountTypes.contains(type)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004229 Bundle result = new Bundle();
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004230 // Need to return just the accounts that are from matching signatures.
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08004231 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004232 try {
4233 response.onResult(result);
4234 } catch (RemoteException e) {
4235 Log.e(TAG, "Cannot respond to caller do to exception." , e);
4236 }
4237 return;
4238 }
Fred Quintana33269202009-04-20 16:05:10 -07004239 long identityToken = clearCallingIdentity();
4240 try {
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004241 UserAccounts userAccounts = getUserAccounts(userId);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004242 if (features == null || features.length == 0) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004243 Account[] accounts;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004244 synchronized (userAccounts.cacheLock) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004245 accounts = getAccountsFromCacheLocked(
4246 userAccounts, type, callingUid, opPackageName, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004247 }
Fred Quintanad4a9d6c2010-02-24 12:07:53 -08004248 Bundle result = new Bundle();
4249 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
4250 onResult(response, result);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07004251 return;
4252 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004253 new GetAccountsByTypeAndFeatureSession(
4254 userAccounts,
4255 response,
4256 type,
4257 features,
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004258 callingUid,
4259 opPackageName).bind();
Fred Quintana33269202009-04-20 16:05:10 -07004260 } finally {
4261 restoreCallingIdentity(identityToken);
Fred Quintana60307342009-03-24 22:48:12 -07004262 }
4263 }
4264
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004265 @Override
4266 public void onAccountAccessed(String token) throws RemoteException {
4267 final int uid = Binder.getCallingUid();
4268 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
4269 return;
4270 }
4271 final int userId = UserHandle.getCallingUserId();
4272 final long identity = Binder.clearCallingIdentity();
4273 try {
4274 for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
4275 if (Objects.equals(account.getAccessId(), token)) {
4276 // An app just accessed the account. At this point it knows about
4277 // it and there is not need to hide this account from the app.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004278 // Do we need to update account visibility here?
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07004279 if (!hasAccountAccess(account, null, uid)) {
4280 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
4281 uid, true);
4282 }
4283 }
4284 }
4285 } finally {
4286 Binder.restoreCallingIdentity(identity);
4287 }
4288 }
4289
Fred Quintanaa698f422009-04-08 19:14:54 -07004290 private abstract class Session extends IAccountAuthenticatorResponse.Stub
Fred Quintanab839afc2009-10-14 15:57:28 -07004291 implements IBinder.DeathRecipient, ServiceConnection {
Fred Quintana60307342009-03-24 22:48:12 -07004292 IAccountManagerResponse mResponse;
4293 final String mAccountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004294 final boolean mExpectActivityLaunch;
4295 final long mCreationTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004296 final String mAccountName;
4297 // Indicates if we need to add auth details(like last credential time)
4298 final boolean mAuthDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004299 // If set, we need to update the last authenticated time. This is
4300 // currently
4301 // used on
4302 // successful confirming credentials.
4303 final boolean mUpdateLastAuthenticatedTime;
Fred Quintanaa698f422009-04-08 19:14:54 -07004304
Fred Quintana33269202009-04-20 16:05:10 -07004305 public int mNumResults = 0;
Fred Quintanaa698f422009-04-08 19:14:54 -07004306 private int mNumRequestContinued = 0;
4307 private int mNumErrors = 0;
4308
Fred Quintana60307342009-03-24 22:48:12 -07004309 IAccountAuthenticator mAuthenticator = null;
4310
Fred Quintana8570f742010-02-18 10:32:54 -08004311 private final boolean mStripAuthTokenFromResult;
Amith Yamasani04e0d262012-02-14 11:50:53 -08004312 protected final UserAccounts mAccounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004313
Amith Yamasani04e0d262012-02-14 11:50:53 -08004314 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004315 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4316 boolean authDetailsRequired) {
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004317 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
4318 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
4319 }
4320
4321 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
4322 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
4323 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
Fred Quintana60307342009-03-24 22:48:12 -07004324 super();
Amith Yamasani67df64b2012-12-14 12:09:36 -08004325 //if (response == null) throw new IllegalArgumentException("response is null");
Fred Quintana33269202009-04-20 16:05:10 -07004326 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Amith Yamasani04e0d262012-02-14 11:50:53 -08004327 mAccounts = accounts;
Fred Quintana8570f742010-02-18 10:32:54 -08004328 mStripAuthTokenFromResult = stripAuthTokenFromResult;
Fred Quintana60307342009-03-24 22:48:12 -07004329 mResponse = response;
4330 mAccountType = accountType;
Fred Quintanaa698f422009-04-08 19:14:54 -07004331 mExpectActivityLaunch = expectActivityLaunch;
4332 mCreationTime = SystemClock.elapsedRealtime();
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004333 mAccountName = accountName;
4334 mAuthDetailsRequired = authDetailsRequired;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004335 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004336
Fred Quintanaa698f422009-04-08 19:14:54 -07004337 synchronized (mSessions) {
4338 mSessions.put(toString(), this);
4339 }
Amith Yamasani67df64b2012-12-14 12:09:36 -08004340 if (response != null) {
4341 try {
4342 response.asBinder().linkToDeath(this, 0 /* flags */);
4343 } catch (RemoteException e) {
4344 mResponse = null;
4345 binderDied();
4346 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004347 }
Fred Quintana60307342009-03-24 22:48:12 -07004348 }
4349
Fred Quintanaa698f422009-04-08 19:14:54 -07004350 IAccountManagerResponse getResponseAndClose() {
Fred Quintana60307342009-03-24 22:48:12 -07004351 if (mResponse == null) {
4352 // this session has already been closed
4353 return null;
4354 }
Fred Quintana60307342009-03-24 22:48:12 -07004355 IAccountManagerResponse response = mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07004356 close(); // this clears mResponse so we need to save the response before this call
Fred Quintana60307342009-03-24 22:48:12 -07004357 return response;
4358 }
4359
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004360 /**
4361 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
4362 * security policy.
4363 *
4364 * In particular we want to make sure that the Authenticator doesn't try to trick users
4365 * into launching aribtrary intents on the device via by tricking to click authenticator
4366 * supplied entries in the system Settings app.
4367 */
4368 protected void checkKeyIntent(
4369 int authUid,
4370 Intent intent) throws SecurityException {
4371 long bid = Binder.clearCallingIdentity();
4372 try {
4373 PackageManager pm = mContext.getPackageManager();
4374 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
4375 ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
4376 int targetUid = targetActivityInfo.applicationInfo.uid;
Sandra Kwan0e961a12016-06-30 14:34:01 -07004377 if (!GrantCredentialsPermissionActivity.class.getName().equals(
4378 targetActivityInfo.getClass().getName())
4379 && !CantAddAccountActivity.class
4380 .equals(targetActivityInfo.getClass().getName())
4381 && PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid,
4382 targetUid)) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004383 String pkgName = targetActivityInfo.packageName;
4384 String activityName = targetActivityInfo.name;
4385 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
4386 + "does not share a signature with the supplying authenticator (%s).";
4387 throw new SecurityException(
4388 String.format(tmpl, activityName, pkgName, mAccountType));
4389 }
4390 } finally {
4391 Binder.restoreCallingIdentity(bid);
4392 }
4393 }
4394
Fred Quintanaa698f422009-04-08 19:14:54 -07004395 private void close() {
4396 synchronized (mSessions) {
4397 if (mSessions.remove(toString()) == null) {
4398 // the session was already closed, so bail out now
4399 return;
4400 }
4401 }
4402 if (mResponse != null) {
4403 // stop listening for response deaths
4404 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
4405
4406 // clear this so that we don't accidentally send any further results
4407 mResponse = null;
4408 }
4409 cancelTimeout();
4410 unbind();
4411 }
4412
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004413 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004414 public void binderDied() {
4415 mResponse = null;
4416 close();
4417 }
4418
4419 protected String toDebugString() {
4420 return toDebugString(SystemClock.elapsedRealtime());
4421 }
4422
4423 protected String toDebugString(long now) {
4424 return "Session: expectLaunch " + mExpectActivityLaunch
4425 + ", connected " + (mAuthenticator != null)
4426 + ", stats (" + mNumResults + "/" + mNumRequestContinued
4427 + "/" + mNumErrors + ")"
4428 + ", lifetime " + ((now - mCreationTime) / 1000.0);
4429 }
4430
Fred Quintana60307342009-03-24 22:48:12 -07004431 void bind() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004432 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4433 Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
4434 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004435 if (!bindToAuthenticator(mAccountType)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004436 Log.d(TAG, "bind attempt failed for " + toDebugString());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004437 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
Fred Quintana60307342009-03-24 22:48:12 -07004438 }
4439 }
4440
4441 private void unbind() {
4442 if (mAuthenticator != null) {
4443 mAuthenticator = null;
Fred Quintanab839afc2009-10-14 15:57:28 -07004444 mContext.unbindService(this);
Fred Quintana60307342009-03-24 22:48:12 -07004445 }
4446 }
4447
Fred Quintana60307342009-03-24 22:48:12 -07004448 public void cancelTimeout() {
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004449 mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
Fred Quintana60307342009-03-24 22:48:12 -07004450 }
4451
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004452 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004453 public void onServiceConnected(ComponentName name, IBinder service) {
Fred Quintana60307342009-03-24 22:48:12 -07004454 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
Fred Quintanaa698f422009-04-08 19:14:54 -07004455 try {
4456 run();
4457 } catch (RemoteException e) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004458 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
Fred Quintanaa698f422009-04-08 19:14:54 -07004459 "remote exception");
4460 }
Fred Quintana60307342009-03-24 22:48:12 -07004461 }
4462
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004463 @Override
Fred Quintanab839afc2009-10-14 15:57:28 -07004464 public void onServiceDisconnected(ComponentName name) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004465 mAuthenticator = null;
4466 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004467 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004468 try {
4469 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4470 "disconnected");
4471 } catch (RemoteException e) {
4472 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4473 Log.v(TAG, "Session.onServiceDisconnected: "
4474 + "caught RemoteException while responding", e);
4475 }
4476 }
Fred Quintana60307342009-03-24 22:48:12 -07004477 }
4478 }
4479
Fred Quintanab839afc2009-10-14 15:57:28 -07004480 public abstract void run() throws RemoteException;
4481
Fred Quintana60307342009-03-24 22:48:12 -07004482 public void onTimedOut() {
Fred Quintanaa698f422009-04-08 19:14:54 -07004483 IAccountManagerResponse response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004484 if (response != null) {
Fred Quintana166466d2011-10-24 14:51:40 -07004485 try {
4486 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
4487 "timeout");
4488 } catch (RemoteException e) {
4489 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4490 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
4491 e);
4492 }
4493 }
Fred Quintana60307342009-03-24 22:48:12 -07004494 }
4495 }
4496
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004497 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004498 public void onResult(Bundle result) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06004499 Bundle.setDefusable(result, true);
Fred Quintanaa698f422009-04-08 19:14:54 -07004500 mNumResults++;
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004501 Intent intent = null;
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004502 if (result != null) {
4503 boolean isSuccessfulConfirmCreds = result.getBoolean(
4504 AccountManager.KEY_BOOLEAN_RESULT, false);
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004505 boolean isSuccessfulUpdateCredsOrAddAccount =
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004506 result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
4507 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
Carlos Valdivia91979be2015-05-22 14:11:35 -07004508 // We should only update lastAuthenticated time, if
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004509 // mUpdateLastAuthenticatedTime is true and the confirmRequest
4510 // or updateRequest was successful
Carlos Valdivia91979be2015-05-22 14:11:35 -07004511 boolean needUpdate = mUpdateLastAuthenticatedTime
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07004512 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004513 if (needUpdate || mAuthDetailsRequired) {
4514 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
4515 if (needUpdate && accountPresent) {
4516 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType));
4517 }
4518 if (mAuthDetailsRequired) {
4519 long lastAuthenticatedTime = -1;
4520 if (accountPresent) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004521 lastAuthenticatedTime = mAccounts.accountsDb
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004522 .findAccountLastAuthenticatedTime(
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004523 new Account(mAccountName, mAccountType));
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004524 }
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07004525 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07004526 lastAuthenticatedTime);
4527 }
4528 }
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08004529 }
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004530 if (result != null
4531 && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
Carlos Valdivia6ede9c32016-03-10 20:12:32 -08004532 checkKeyIntent(
4533 Binder.getCallingUid(),
4534 intent);
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004535 }
4536 if (result != null
4537 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004538 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
4539 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004540 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
4541 Account account = new Account(accountName, accountType);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07004542 cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
4543 new UserHandle(mAccounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004544 }
Fred Quintana60307342009-03-24 22:48:12 -07004545 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004546 IAccountManagerResponse response;
4547 if (mExpectActivityLaunch && result != null
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004548 && result.containsKey(AccountManager.KEY_INTENT)) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004549 response = mResponse;
4550 } else {
4551 response = getResponseAndClose();
Fred Quintana60307342009-03-24 22:48:12 -07004552 }
Fred Quintana60307342009-03-24 22:48:12 -07004553 if (response != null) {
4554 try {
Fred Quintanaa698f422009-04-08 19:14:54 -07004555 if (result == null) {
Fred Quintana56285a62010-12-02 14:20:51 -08004556 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4557 Log.v(TAG, getClass().getSimpleName()
4558 + " calling onError() on response " + response);
4559 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07004560 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
Fred Quintanaa698f422009-04-08 19:14:54 -07004561 "null bundle returned");
4562 } else {
Fred Quintana8570f742010-02-18 10:32:54 -08004563 if (mStripAuthTokenFromResult) {
4564 result.remove(AccountManager.KEY_AUTHTOKEN);
4565 }
Fred Quintana56285a62010-12-02 14:20:51 -08004566 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4567 Log.v(TAG, getClass().getSimpleName()
4568 + " calling onResult() on response " + response);
4569 }
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004570 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
4571 (intent == null)) {
4572 // All AccountManager error codes are greater than 0
4573 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
4574 result.getString(AccountManager.KEY_ERROR_MESSAGE));
4575 } else {
4576 response.onResult(result);
4577 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004578 }
Fred Quintana60307342009-03-24 22:48:12 -07004579 } catch (RemoteException e) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004580 // if the caller is dead then there is no one to care about remote exceptions
4581 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4582 Log.v(TAG, "failure while notifying response", e);
4583 }
Fred Quintana60307342009-03-24 22:48:12 -07004584 }
4585 }
4586 }
Fred Quintana60307342009-03-24 22:48:12 -07004587
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004588 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -07004589 public void onRequestContinued() {
4590 mNumRequestContinued++;
Fred Quintana60307342009-03-24 22:48:12 -07004591 }
4592
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08004593 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004594 public void onError(int errorCode, String errorMessage) {
Fred Quintanaa698f422009-04-08 19:14:54 -07004595 mNumErrors++;
Fred Quintanaa698f422009-04-08 19:14:54 -07004596 IAccountManagerResponse response = getResponseAndClose();
4597 if (response != null) {
4598 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Fred Quintana56285a62010-12-02 14:20:51 -08004599 Log.v(TAG, getClass().getSimpleName()
4600 + " calling onError() on response " + response);
Fred Quintanaa698f422009-04-08 19:14:54 -07004601 }
4602 try {
4603 response.onError(errorCode, errorMessage);
4604 } catch (RemoteException e) {
4605 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4606 Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
4607 }
4608 }
4609 } else {
4610 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4611 Log.v(TAG, "Session.onError: already closed");
4612 }
Fred Quintana60307342009-03-24 22:48:12 -07004613 }
4614 }
Fred Quintanab839afc2009-10-14 15:57:28 -07004615
4616 /**
4617 * find the component name for the authenticator and initiate a bind
4618 * if no authenticator or the bind fails then return false, otherwise return true
4619 */
4620 private boolean bindToAuthenticator(String authenticatorType) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004621 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
4622 authenticatorInfo = mAuthenticatorCache.getServiceInfo(
4623 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
Fred Quintanab839afc2009-10-14 15:57:28 -07004624 if (authenticatorInfo == null) {
4625 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4626 Log.v(TAG, "there is no authenticator for " + authenticatorType
4627 + ", bailing out");
4628 }
4629 return false;
4630 }
4631
Jeff Sharkeyce18c812016-04-27 16:00:41 -06004632 if (!isLocalUnlockedUser(mAccounts.userId)
Jeff Sharkey8a372a02016-03-16 16:25:45 -06004633 && !authenticatorInfo.componentInfo.directBootAware) {
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07004634 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
4635 + " which isn't encryption aware");
4636 return false;
4637 }
4638
Fred Quintanab839afc2009-10-14 15:57:28 -07004639 Intent intent = new Intent();
4640 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
4641 intent.setComponent(authenticatorInfo.componentName);
4642 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4643 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
4644 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08004645 if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004646 UserHandle.of(mAccounts.userId))) {
Fred Quintanab839afc2009-10-14 15:57:28 -07004647 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4648 Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
4649 }
4650 return false;
4651 }
4652
Fred Quintanab839afc2009-10-14 15:57:28 -07004653 return true;
4654 }
Fred Quintana60307342009-03-24 22:48:12 -07004655 }
4656
Svet Ganov5d09c992016-09-07 09:57:41 -07004657 class MessageHandler extends Handler {
Fred Quintana60307342009-03-24 22:48:12 -07004658 MessageHandler(Looper looper) {
4659 super(looper);
4660 }
Costin Manolache3348f142009-09-29 18:58:36 -07004661
Carlos Valdivia5bab9da2013-09-29 05:11:56 -07004662 @Override
Fred Quintana60307342009-03-24 22:48:12 -07004663 public void handleMessage(Message msg) {
Fred Quintana60307342009-03-24 22:48:12 -07004664 switch (msg.what) {
4665 case MESSAGE_TIMED_OUT:
4666 Session session = (Session)msg.obj;
4667 session.onTimedOut();
4668 break;
4669
Amith Yamasani5be347b2013-03-31 17:44:31 -07004670 case MESSAGE_COPY_SHARED_ACCOUNT:
Esteban Talavera22dc3b72014-10-31 15:41:12 +00004671 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
Amith Yamasani5be347b2013-03-31 17:44:31 -07004672 break;
4673
Fred Quintana60307342009-03-24 22:48:12 -07004674 default:
4675 throw new IllegalStateException("unhandled message: " + msg.what);
4676 }
4677 }
4678 }
4679
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004680 private void logRecord(UserAccounts accounts, String action, String tableName) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004681 logRecord(action, tableName, -1, accounts);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004682 }
4683
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004684 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004685 logRecord(action, tableName, -1, accounts, uid);
Simranjit Singh Kohliba0b10a2015-07-16 20:33:14 -07004686 }
4687
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004688 /*
4689 * This function receives an opened writable database.
4690 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004691 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004692 UserAccounts userAccount) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004693 logRecord(action, tableName, accountId, userAccount, getCallingUid());
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004694 }
4695
4696 /*
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004697 * This function receives an opened writable database and writes to it in a separate thread.
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004698 */
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004699 private void logRecord(String action, String tableName, long accountId,
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004700 UserAccounts userAccount, int callingUid) {
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004701
4702 class LogRecordTask implements Runnable {
4703 private final String action;
4704 private final String tableName;
4705 private final long accountId;
4706 private final UserAccounts userAccount;
4707 private final int callingUid;
4708 private final long userDebugDbInsertionPoint;
4709
4710 LogRecordTask(final String action,
4711 final String tableName,
4712 final long accountId,
4713 final UserAccounts userAccount,
4714 final int callingUid,
4715 final long userDebugDbInsertionPoint) {
4716 this.action = action;
4717 this.tableName = tableName;
4718 this.accountId = accountId;
4719 this.userAccount = userAccount;
4720 this.callingUid = callingUid;
4721 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint;
4722 }
4723
4724 public void run() {
4725 SQLiteStatement logStatement = userAccount.statementForLogging;
4726 logStatement.bindLong(1, accountId);
4727 logStatement.bindString(2, action);
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07004728 logStatement.bindString(3, mDateFormat.format(new Date()));
Tejas Khorana7b88f0e2016-06-13 13:06:35 -07004729 logStatement.bindLong(4, callingUid);
4730 logStatement.bindString(5, tableName);
4731 logStatement.bindLong(6, userDebugDbInsertionPoint);
4732 logStatement.execute();
4733 logStatement.clearBindings();
4734 }
4735 }
4736
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004737 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
4738 callingUid, userAccount.debugDbInsertionPoint);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004739 userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004740 % AccountsDb.MAX_DEBUG_DB_SIZE;
Fyodor Kupolov8873aa32016-08-25 15:25:40 -07004741 mHandler.post(logTask);
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004742 }
4743
4744 /*
4745 * This should only be called once to compile the sql statement for logging
4746 * and to find the insertion point.
4747 */
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004748 private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
4749 userAccount.debugDbInsertionPoint = userAccount.accountsDb
4750 .calculateDebugTableInsertionPoint();
4751 userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07004752 }
4753
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004754 public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
Fred Quintana60307342009-03-24 22:48:12 -07004755 return asBinder();
4756 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004757
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004758 /**
4759 * Searches array of arguments for the specified string
4760 * @param args array of argument strings
4761 * @param value value to search for
4762 * @return true if the value is contained in the array
4763 */
4764 private static boolean scanArgs(String[] args, String value) {
4765 if (args != null) {
4766 for (String arg : args) {
4767 if (value.equals(arg)) {
4768 return true;
4769 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004770 }
4771 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004772 return false;
4773 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004774
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004775 @Override
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004776 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Kenny Root3abd75b2011-09-29 11:00:41 -07004777 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4778 != PackageManager.PERMISSION_GRANTED) {
4779 fout.println("Permission Denial: can't dump AccountsManager from from pid="
4780 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
4781 + " without permission " + android.Manifest.permission.DUMP);
4782 return;
4783 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08004784 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004785 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " ");
Kenny Root3abd75b2011-09-29 11:00:41 -07004786
Jeff Sharkey6eb96202012-10-10 13:13:54 -07004787 final List<UserInfo> users = getUserManager().getUsers();
4788 for (UserInfo user : users) {
4789 ipw.println("User " + user + ":");
4790 ipw.increaseIndent();
4791 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
4792 ipw.println();
4793 ipw.decreaseIndent();
Amith Yamasani04e0d262012-02-14 11:50:53 -08004794 }
4795 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004796
Amith Yamasani04e0d262012-02-14 11:50:53 -08004797 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
4798 String[] args, boolean isCheckinRequest) {
4799 synchronized (userAccounts.cacheLock) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004800 if (isCheckinRequest) {
4801 // This is a checkin request. *Only* upload the account types and the count of each.
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004802 userAccounts.accountsDb.dumpDeAccountsTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004803 } else {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004804 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Dmitry Dementyeve366f822017-01-31 10:25:10 -08004805 Process.SYSTEM_UID, null /* packageName */, false);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004806 fout.println("Accounts: " + accounts.length);
4807 for (Account account : accounts) {
4808 fout.println(" " + account);
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004809 }
Fred Quintana307da1a2010-01-21 14:24:20 -08004810
Simranjit Singh Kohli1d0c1a62015-04-09 13:58:44 -07004811 // Add debug information.
4812 fout.println();
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07004813 userAccounts.accountsDb.dumpDebugTable(fout);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004814 fout.println();
4815 synchronized (mSessions) {
4816 final long now = SystemClock.elapsedRealtime();
4817 fout.println("Active Sessions: " + mSessions.size());
4818 for (Session session : mSessions.values()) {
4819 fout.println(" " + session.toDebugString(now));
4820 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004821 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004822
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004823 fout.println();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004824 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08004825 }
Jason Parks1cd7d0e2009-09-28 14:48:34 -07004826 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004827 }
4828
Amith Yamasani04e0d262012-02-14 11:50:53 -08004829 private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004830 Intent intent, String packageName, final int userId) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004831 long identityToken = clearCallingIdentity();
4832 try {
4833 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4834 Log.v(TAG, "doNotification: " + message + " intent:" + intent);
4835 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004836
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004837 if (intent.getComponent() != null &&
4838 GrantCredentialsPermissionActivity.class.getName().equals(
4839 intent.getComponent().getClassName())) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004840 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004841 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004842 Context contextForUser = getContextForUser(new UserHandle(userId));
Amith Yamasani04e0d262012-02-14 11:50:53 -08004843 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
Fred Quintana33f889a2009-09-14 17:31:26 -07004844 intent.addCategory(String.valueOf(notificationId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004845
Fred Quintana33f889a2009-09-14 17:31:26 -07004846 final String notificationTitleFormat =
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004847 contextForUser.getText(R.string.notification_title).toString();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004848 Notification n =
4849 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004850 .setWhen(0)
4851 .setSmallIcon(android.R.drawable.stat_sys_warning)
4852 .setColor(contextForUser.getColor(
4853 com.android.internal.R.color.system_notification_accent_color))
4854 .setContentTitle(String.format(notificationTitleFormat, account.name))
4855 .setContentText(message)
4856 .setContentIntent(PendingIntent.getActivityAsUser(
4857 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004858 null, new UserHandle(userId)))
Chris Wren1ce4b6d2015-06-11 10:19:43 -04004859 .build();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004860 installNotification(notificationId, n, packageName, userId);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004861 }
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004862 } finally {
4863 restoreCallingIdentity(identityToken);
4864 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004865 }
4866
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004867 private void installNotification(int notificationId, final Notification notification,
4868 String packageName, int userId) {
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004869 SystemNotificationChannels.createAccountChannelForPackage(packageName, mContext);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004870 final long token = clearCallingIdentity();
4871 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004872 INotificationManager notificationManager = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004873 try {
4874 notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
4875 notificationId, notification, new int[1], userId);
4876 } catch (RemoteException e) {
4877 /* ignore - local call */
4878 }
4879 } finally {
4880 Binder.restoreCallingIdentity(token);
4881 }
Fred Quintana56285a62010-12-02 14:20:51 -08004882 }
4883
Fyodor Kupolovda993802016-09-21 14:47:10 -07004884 private void cancelNotification(int id, UserHandle user) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004885 cancelNotification(id, mContext.getPackageName(), user);
4886 }
4887
Fyodor Kupolovda993802016-09-21 14:47:10 -07004888 private void cancelNotification(int id, String packageName, UserHandle user) {
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004889 long identityToken = clearCallingIdentity();
4890 try {
Fyodor Kupolovda993802016-09-21 14:47:10 -07004891 INotificationManager service = mInjector.getNotificationManager();
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004892 service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
4893 } catch (RemoteException e) {
4894 /* ignore - local call */
Fred Quintana26fc5eb2009-04-09 15:05:50 -07004895 } finally {
4896 restoreCallingIdentity(identityToken);
4897 }
Fred Quintanaa698f422009-04-08 19:14:54 -07004898 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004899
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004900 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) {
4901 final long identity = Binder.clearCallingIdentity();
4902 try {
4903 IPackageManager pm = ActivityThread.getPackageManager();
4904 for (String perm : permissions) {
4905 if (pm.checkPermission(perm, packageName, userId)
4906 == PackageManager.PERMISSION_GRANTED) {
4907 return true;
4908 }
4909 }
4910 } catch (RemoteException e) {
4911 /* ignore - local call */
4912 } finally {
4913 Binder.restoreCallingIdentity(identity);
4914 }
4915 return false;
4916 }
4917
Ian Pedowitz358e51f2016-03-15 17:08:27 +00004918 private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
4919 for (String perm : permissions) {
4920 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
4921 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4922 Log.v(TAG, " caller uid " + callingUid + " has " + perm);
4923 }
4924 final int opCode = AppOpsManager.permissionToOpCode(perm);
4925 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
4926 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
4927 return true;
4928 }
4929 }
4930 }
4931 return false;
4932 }
Carlos Valdiviac37ee222015-06-17 20:17:37 -07004933
Amith Yamasani67df64b2012-12-14 12:09:36 -08004934 private int handleIncomingUser(int userId) {
4935 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004936 return ActivityManager.getService().handleIncomingUser(
Amith Yamasani67df64b2012-12-14 12:09:36 -08004937 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
4938 } catch (RemoteException re) {
4939 // Shouldn't happen, local.
4940 }
4941 return userId;
4942 }
4943
Christopher Tateccbf84f2013-05-08 15:25:41 -07004944 private boolean isPrivileged(int callingUid) {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004945 String[] packages;
4946 long identityToken = Binder.clearCallingIdentity();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004947 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004948 packages = mPackageManager.getPackagesForUid(callingUid);
4949 } finally {
4950 Binder.restoreCallingIdentity(identityToken);
4951 }
4952 if (packages == null) {
4953 Log.d(TAG, "No packages for callingUid " + callingUid);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07004954 return false;
4955 }
Fred Quintana7be59642009-08-24 18:29:25 -07004956 for (String name : packages) {
4957 try {
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08004958 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
Fred Quintana56285a62010-12-02 14:20:51 -08004959 if (packageInfo != null
Alex Klyubinb9f8a522015-02-03 11:12:59 -08004960 && (packageInfo.applicationInfo.privateFlags
4961 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
Fred Quintana7be59642009-08-24 18:29:25 -07004962 return true;
4963 }
4964 } catch (PackageManager.NameNotFoundException e) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08004965 Log.d(TAG, "Package not found " + e.getMessage());
Fred Quintana7be59642009-08-24 18:29:25 -07004966 return false;
4967 }
4968 }
4969 return false;
4970 }
4971
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00004972 private boolean permissionIsGranted(
4973 Account account, String authTokenType, int callerUid, int userId) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004974 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
4975 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4976 Log.v(TAG, "Access to " + account + " granted calling uid is system");
4977 }
4978 return true;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07004979 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07004980
4981 if (isPrivileged(callerUid)) {
4982 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4983 Log.v(TAG, "Access to " + account + " granted calling uid "
4984 + callerUid + " privileged");
4985 }
4986 return true;
4987 }
4988 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
4989 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4990 Log.v(TAG, "Access to " + account + " granted calling uid "
4991 + callerUid + " manages the account");
4992 }
4993 return true;
4994 }
4995 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
4996 if (Log.isLoggable(TAG, Log.VERBOSE)) {
4997 Log.v(TAG, "Access to " + account + " granted calling uid "
4998 + callerUid + " user granted access");
4999 }
5000 return true;
5001 }
5002
5003 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5004 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
5005 }
5006
5007 return false;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005008 }
5009
Svetoslavf3f02ac2015-09-08 14:36:35 -07005010 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
5011 String opPackageName) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005012 if (accountType == null) {
5013 return false;
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005014 } else {
Svetoslavf3f02ac2015-09-08 14:36:35 -07005015 return getTypesVisibleToCaller(callingUid, userId,
5016 opPackageName).contains(accountType);
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005017 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005018 }
5019
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005020 // Method checks visibility for applications targeing API level below {@link
5021 // android.os.Build.VERSION_CODES#O},
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005022 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005023 private boolean checkGetAccountsPermission(String packageName, int userId) {
5024 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
5025 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
5026 }
5027
5028 private boolean checkReadContactsPermission(String packageName, int userId) {
5029 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS);
5030 }
5031
5032 /**
5033 * Method checks package uid and signature with Authenticator which manages accountType.
5034 *
5035 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
5036 * SIGNATURE_CHECK_MISMATCH otherwise.
5037 */
5038 private int checkPackageSignature(String accountType, int callingUid, int userId) {
5039 if (accountType == null) {
5040 return SIGNATURE_CHECK_MISMATCH;
5041 }
5042
5043 long identityToken = Binder.clearCallingIdentity();
5044 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5045 try {
5046 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5047 } finally {
5048 Binder.restoreCallingIdentity(identityToken);
5049 }
5050 // Check for signature match with Authenticator.
5051 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
5052 : serviceInfos) {
5053 if (accountType.equals(serviceInfo.type.type)) {
5054 if (serviceInfo.uid == callingUid) {
5055 return SIGNATURE_CHECK_UID_MATCH;
5056 }
5057 final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
5058 if (sigChk == PackageManager.SIGNATURE_MATCH) {
5059 return SIGNATURE_CHECK_MATCH;
5060 }
5061 }
5062 }
5063 return SIGNATURE_CHECK_MISMATCH;
5064 }
5065
5066 // returns true for applications with the same signature as authenticator.
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005067 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
5068 if (accountType == null) {
5069 return false;
5070 } else {
5071 return getTypesManagedByCaller(callingUid, userId).contains(accountType);
5072 }
5073 }
5074
Svetoslavf3f02ac2015-09-08 14:36:35 -07005075 private List<String> getTypesVisibleToCaller(int callingUid, int userId,
5076 String opPackageName) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005077 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005078 }
5079
5080 private List<String> getTypesManagedByCaller(int callingUid, int userId) {
Dmitry Dementyev2e22cfb2017-01-09 18:42:14 +00005081 return getTypesForCaller(callingUid, userId, false);
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005082 }
5083
5084 private List<String> getTypesForCaller(
5085 int callingUid, int userId, boolean isOtherwisePermitted) {
5086 List<String> managedAccountTypes = new ArrayList<>();
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005087 long identityToken = Binder.clearCallingIdentity();
5088 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
5089 try {
5090 serviceInfos = mAuthenticatorCache.getAllServices(userId);
5091 } finally {
5092 Binder.restoreCallingIdentity(identityToken);
5093 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005094 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
Simranjit Singh Kohlib77d8b62015-08-07 17:07:23 -07005095 serviceInfos) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005096 if (isOtherwisePermitted || (mPackageManager.checkSignatures(serviceInfo.uid,
5097 callingUid) == PackageManager.SIGNATURE_MATCH)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005098 managedAccountTypes.add(serviceInfo.type.type);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005099 }
5100 }
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005101 return managedAccountTypes;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005102 }
5103
Simranjit Singh Kohli82d01782015-04-09 17:27:06 -07005104 private boolean isAccountPresentForCaller(String accountName, String accountType) {
5105 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) {
5106 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) {
5107 if (account.name.equals(accountName)) {
5108 return true;
5109 }
5110 }
5111 }
5112 return false;
5113 }
5114
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07005115 private static void checkManageUsersPermission(String message) {
5116 if (ActivityManager.checkComponentPermission(
5117 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
5118 != PackageManager.PERMISSION_GRANTED) {
5119 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
5120 }
5121 }
5122
Sudheer Shanka3b2297d2016-06-20 10:44:30 -07005123 private static void checkManageOrCreateUsersPermission(String message) {
5124 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS,
5125 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED &&
5126 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS,
5127 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
5128 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: "
5129 + message);
5130 }
5131 }
5132
Amith Yamasani04e0d262012-02-14 11:50:53 -08005133 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
5134 int callerUid) {
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005135 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005136 return true;
5137 }
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005138 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005139 synchronized (accounts.cacheLock) {
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005140 long grantsCount;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005141 if (authTokenType != null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005142 grantsCount = accounts.accountsDb.findMatchingGrantsCount(callerUid, authTokenType,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005143 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005144 } else {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005145 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005146 account);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005147 }
Fyodor Kupolov1ce01612016-08-26 11:39:07 -07005148 final boolean permissionGranted = grantsCount > 0;
Svet Ganov890a2102016-08-24 00:08:00 -07005149
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005150 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
5151 // TODO: Skip this check when running automated tests. Replace this
5152 // with a more general solution.
5153 Log.d(TAG, "no credentials permission for usage of " + account + ", "
Amith Yamasani04e0d262012-02-14 11:50:53 -08005154 + authTokenType + " by uid " + callerUid
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005155 + " but ignoring since device is in test harness.");
5156 return true;
5157 }
5158 return permissionGranted;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005159 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005160 }
5161
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005162 private boolean isSystemUid(int callingUid) {
5163 String[] packages = null;
5164 long ident = Binder.clearCallingIdentity();
5165 try {
5166 packages = mPackageManager.getPackagesForUid(callingUid);
5167 } finally {
5168 Binder.restoreCallingIdentity(ident);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005169 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005170 if (packages != null) {
5171 for (String name : packages) {
5172 try {
5173 PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
5174 if (packageInfo != null
5175 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
5176 != 0) {
5177 return true;
5178 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005179 } catch (NameNotFoundException e) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005180 Log.w(TAG, String.format("Could not find package [%s]", name), e);
5181 }
5182 }
5183 } else {
5184 Log.w(TAG, "No known packages with uid " + callingUid);
Carlos Valdiviaffb46022015-06-08 19:07:54 -07005185 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07005186 return false;
Carlos Valdiviadcddc472015-06-11 20:04:04 +00005187 }
5188
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005189 /** Succeeds if any of the specified permissions are granted. */
5190 private void checkReadAccountsPermitted(
5191 int callingUid,
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00005192 String accountType,
Svetoslavf3f02ac2015-09-08 14:36:35 -07005193 int userId,
5194 String opPackageName) {
5195 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005196 String msg = String.format(
5197 "caller uid %s cannot access %s accounts",
5198 callingUid,
5199 accountType);
5200 Log.w(TAG, " " + msg);
5201 throw new SecurityException(msg);
5202 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005203 }
5204
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005205 private boolean canUserModifyAccounts(int userId, int callingUid) {
5206 // the managing app can always modify accounts
5207 if (isProfileOwner(callingUid)) {
5208 return true;
5209 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005210 if (getUserManager().getUserRestrictions(new UserHandle(userId))
5211 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
5212 return false;
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005213 }
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005214 return true;
5215 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005216
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005217 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
5218 // the managing app can always modify accounts
5219 if (isProfileOwner(callingUid)) {
5220 return true;
5221 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005222 DevicePolicyManager dpm = (DevicePolicyManager) mContext
5223 .getSystemService(Context.DEVICE_POLICY_SERVICE);
Alexandra Gherghina999d3942014-07-03 11:40:08 +01005224 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Adili Muguro4e68b652014-07-25 16:42:39 +02005225 if (typesArray == null) {
5226 return true;
5227 }
Sander Alewijnseda1350f2014-05-08 16:59:42 +01005228 for (String forbiddenType : typesArray) {
5229 if (forbiddenType.equals(accountType)) {
5230 return false;
5231 }
5232 }
Amith Yamasanie4cf7342012-12-17 11:12:09 -08005233 return true;
5234 }
5235
Benjamin Franzb6c0ce42015-11-05 10:06:51 +00005236 private boolean isProfileOwner(int uid) {
5237 final DevicePolicyManagerInternal dpmi =
5238 LocalServices.getService(DevicePolicyManagerInternal.class);
5239 return (dpmi != null)
5240 && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
5241 }
5242
Jatin Lodhia09e7e0e2013-11-07 00:14:25 -08005243 @Override
Fred Quintanad9640ec2012-05-23 12:37:00 -07005244 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
5245 throws RemoteException {
5246 final int callingUid = getCallingUid();
5247
Svetoslav Ganov7ee37f42016-08-24 14:40:16 -07005248 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
Fred Quintanad9640ec2012-05-23 12:37:00 -07005249 throw new SecurityException();
5250 }
5251
5252 if (value) {
5253 grantAppPermission(account, authTokenType, uid);
5254 } else {
5255 revokeAppPermission(account, authTokenType, uid);
5256 }
5257 }
5258
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005259 /**
5260 * Allow callers with the given uid permission to get credentials for account/authTokenType.
5261 * <p>
5262 * Although this is public it can only be accessed via the AccountManagerService object
5263 * which is in the system. This means we don't need to protect it with permissions.
5264 * @hide
5265 */
Svet Ganov5d09c992016-09-07 09:57:41 -07005266 void grantAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005267 if (account == null || authTokenType == null) {
5268 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005269 return;
5270 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005271 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005272 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005273 long accountId = accounts.accountsDb.findDeAccountId(account);
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005274 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005275 accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005276 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005277 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
Fyodor Kupolovef73aaa2016-03-25 10:23:42 -07005278 UserHandle.of(accounts.userId));
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005279
5280 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005281 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005282
5283 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5284 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5285 : mAppPermissionChangeListeners) {
5286 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5287 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005288 }
5289
5290 /**
5291 * Don't allow callers with the given uid permission to get credentials for
5292 * account/authTokenType.
5293 * <p>
5294 * Although this is public it can only be accessed via the AccountManagerService object
5295 * which is in the system. This means we don't need to protect it with permissions.
5296 * @hide
5297 */
Fred Quintanad9640ec2012-05-23 12:37:00 -07005298 private void revokeAppPermission(Account account, String authTokenType, int uid) {
Fred Quintana382601f2010-03-25 12:25:10 -07005299 if (account == null || authTokenType == null) {
5300 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
Fred Quintana31957f12009-10-21 13:43:10 -07005301 return;
5302 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07005303 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
Amith Yamasani04e0d262012-02-14 11:50:53 -08005304 synchronized (accounts.cacheLock) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005305 accounts.accountsDb.beginTransaction();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005306 try {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005307 long accountId = accounts.accountsDb.findDeAccountId(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005308 if (accountId >= 0) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005309 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
5310 accountId, authTokenType, uid);
5311 accounts.accountsDb.setTransactionSuccessful();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005312 }
5313 } finally {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005314 accounts.accountsDb.endTransaction();
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005315 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005316
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07005317 cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
5318 new UserHandle(accounts.userId));
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005319 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07005320
5321 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5322 for (AccountManagerInternal.OnAppPermissionChangeListener listener
5323 : mAppPermissionChangeListeners) {
5324 mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
5325 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07005326 }
Fred Quintana56285a62010-12-02 14:20:51 -08005327
Amith Yamasani04e0d262012-02-14 11:50:53 -08005328 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
5329 final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005330 if (oldAccountsForType != null) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005331 ArrayList<Account> newAccountsList = new ArrayList<>();
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005332 for (Account curAccount : oldAccountsForType) {
5333 if (!curAccount.equals(account)) {
5334 newAccountsList.add(curAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005335 }
5336 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005337 if (newAccountsList.isEmpty()) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005338 accounts.accountCache.remove(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005339 } else {
5340 Account[] newAccountsForType = new Account[newAccountsList.size()];
5341 newAccountsForType = newAccountsList.toArray(newAccountsForType);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005342 accounts.accountCache.put(account.type, newAccountsForType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005343 }
Fred Quintana56285a62010-12-02 14:20:51 -08005344 }
Amith Yamasani04e0d262012-02-14 11:50:53 -08005345 accounts.userDataCache.remove(account);
5346 accounts.authTokenCache.remove(account);
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -07005347 accounts.previousNameCache.remove(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005348 }
5349
5350 /**
5351 * This assumes that the caller has already checked that the account is not already present.
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005352 * IMPORTANT: The account being inserted will begin to be tracked for access in remote
5353 * processes and if you will return this account to apps you should return the result.
5354 * @return The inserted account which is a new instance that is being tracked.
Fred Quintana56285a62010-12-02 14:20:51 -08005355 */
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005356 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005357 Account[] accountsForType = accounts.accountCache.get(account.type);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005358 int oldLength = (accountsForType != null) ? accountsForType.length : 0;
5359 Account[] newAccountsForType = new Account[oldLength + 1];
5360 if (accountsForType != null) {
5361 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
Fred Quintana56285a62010-12-02 14:20:51 -08005362 }
Svet Ganovc1c0d1c2016-09-23 19:15:47 -07005363 String token = account.getAccessId() != null ? account.getAccessId()
5364 : UUID.randomUUID().toString();
5365 newAccountsForType[oldLength] = new Account(account, token);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005366 accounts.accountCache.put(account.type, newAccountsForType);
Svetoslav Ganov57f62592016-09-16 17:29:05 -07005367 return newAccountsForType[oldLength];
Fred Quintana56285a62010-12-02 14:20:51 -08005368 }
5369
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005370 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005371 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
5372 String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005373 String visibilityFilterPackage = callingPackage;
5374 if (visibilityFilterPackage == null) {
5375 visibilityFilterPackage = getPackageNameForUid(callingUid);
5376 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005377 Map<Account, Integer> firstPass = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005378 for (Account account : unfiltered) {
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005379 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005380 if ((visibility == AccountManager.VISIBILITY_VISIBLE
5381 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
5382 || (includeManagedNotVisible
5383 && (visibility
5384 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
5385 firstPass.put(account, visibility);
5386 }
5387 }
5388 Map<Account, Integer> secondPass =
5389 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
5390
5391 Account[] filtered = new Account[secondPass.size()];
5392 filtered = secondPass.keySet().toArray(filtered);
5393 return filtered;
5394 }
5395
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005396 @NonNull
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005397 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005398 @NonNull Map<Account, Integer> unfiltered, int callingUid,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005399 @Nullable String callingPackage) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005400 // first part is to filter shared accounts.
5401 // unfiltered type check is not necessary.
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005402 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005403 || callingUid == Process.SYSTEM_UID) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005404 return unfiltered;
5405 }
Erik Wolsheimerec1a9182016-03-17 10:39:51 -07005406 UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
Amith Yamasani0c19bf52013-10-03 10:34:58 -07005407 if (user != null && user.isRestricted()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005408 String[] packages =
5409 mPackageManager.getPackagesForUid(callingUid);
Dmitry Dementyev5e46e572017-02-16 12:25:49 -08005410 if (packages == null) {
5411 packages = new String[] {};
5412 }
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005413 // If any of the packages is a visible listed package, return the full set,
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005414 // otherwise return non-shared accounts only.
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005415 // This might be a temporary way to specify a visible list
5416 String visibleList = mContext.getResources().getString(
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005417 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
5418 for (String packageName : packages) {
Tejas Khorana5edff3b2016-06-28 20:59:52 -07005419 if (visibleList.contains(";" + packageName + ";")) {
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005420 return unfiltered;
5421 }
5422 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005423 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005424 if (ArrayUtils.isEmpty(sharedAccounts)) {
5425 return unfiltered;
5426 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005427 String requiredAccountType = "";
5428 try {
Amith Yamasanie3423092013-05-22 19:41:45 -07005429 // If there's an explicit callingPackage specified, check if that package
5430 // opted in to see restricted accounts.
5431 if (callingPackage != null) {
5432 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0);
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005433 if (pi != null && pi.restrictedAccountType != null) {
5434 requiredAccountType = pi.restrictedAccountType;
Amith Yamasanie3423092013-05-22 19:41:45 -07005435 }
5436 } else {
5437 // Otherwise check if the callingUid has a package that has opted in
5438 for (String packageName : packages) {
5439 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
5440 if (pi != null && pi.restrictedAccountType != null) {
5441 requiredAccountType = pi.restrictedAccountType;
Amith Yamasani27db4682013-03-30 17:07:47 -07005442 break;
5443 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005444 }
5445 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005446 } catch (NameNotFoundException e) {
5447 Log.d(TAG, "Package not found " + e.getMessage());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005448 }
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005449 Map<Account, Integer> filtered = new LinkedHashMap<>();
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005450 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
5451 Account account = entry.getKey();
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005452 if (account.type.equals(requiredAccountType)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005453 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005454 } else {
5455 boolean found = false;
5456 for (Account shared : sharedAccounts) {
5457 if (shared.equals(account)) {
5458 found = true;
5459 break;
5460 }
5461 }
5462 if (!found) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005463 filtered.put(account, entry.getValue());
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07005464 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005465 }
5466 }
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005467 return filtered;
5468 } else {
5469 return unfiltered;
5470 }
5471 }
5472
Amith Yamasani27db4682013-03-30 17:07:47 -07005473 /*
5474 * packageName can be null. If not null, it should be used to filter out restricted accounts
5475 * that the package is not allowed to access.
5476 */
Dmitry Dementyevc34a48d2017-03-02 13:53:31 -08005477 @NonNull
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08005478 protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
Dmitry Dementyev5159f432017-03-09 12:59:56 -08005479 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Dmitry Dementyeve366f822017-01-31 10:25:10 -08005480 if (callingPackage == null) {
5481 callingPackage = getPackageNameForUid(callingUid);
5482 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005483 if (accountType != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08005484 final Account[] accounts = userAccounts.accountCache.get(accountType);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005485 if (accounts == null) {
5486 return EMPTY_ACCOUNT_ARRAY;
Fred Quintana56285a62010-12-02 14:20:51 -08005487 } else {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005488 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
5489 callingUid, callingPackage, includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005490 }
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005491 } else {
5492 int totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005493 for (Account[] accounts : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005494 totalLength += accounts.length;
5495 }
5496 if (totalLength == 0) {
5497 return EMPTY_ACCOUNT_ARRAY;
5498 }
5499 Account[] accounts = new Account[totalLength];
5500 totalLength = 0;
Amith Yamasani04e0d262012-02-14 11:50:53 -08005501 for (Account[] accountsOfType : userAccounts.accountCache.values()) {
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005502 System.arraycopy(accountsOfType, 0, accounts, totalLength,
5503 accountsOfType.length);
5504 totalLength += accountsOfType.length;
5505 }
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005506 return filterAccounts(userAccounts, accounts, callingUid, callingPackage,
5507 includeManagedNotVisible);
Fred Quintana56285a62010-12-02 14:20:51 -08005508 }
5509 }
5510
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005511 protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005512 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005513 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005514 if (userDataForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005515 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005516 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005517 }
5518 if (value == null) {
5519 userDataForAccount.remove(key);
5520 } else {
5521 userDataForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005522 }
5523 }
5524
Carlos Valdivia91979be2015-05-22 14:11:35 -07005525 protected String readCachedTokenInternal(
5526 UserAccounts accounts,
5527 Account account,
5528 String tokenType,
5529 String callingPackage,
5530 byte[] pkgSigDigest) {
5531 synchronized (accounts.cacheLock) {
Carlos Valdiviac37ee222015-06-17 20:17:37 -07005532 return accounts.accountTokenCaches.get(
5533 account, tokenType, callingPackage, pkgSigDigest);
Carlos Valdivia91979be2015-05-22 14:11:35 -07005534 }
5535 }
5536
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005537 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Amith Yamasani04e0d262012-02-14 11:50:53 -08005538 Account account, String key, String value) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005539 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005540 if (authTokensForAccount == null) {
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005541 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005542 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintanaf9f240e2011-02-24 18:27:50 -08005543 }
5544 if (value == null) {
5545 authTokensForAccount.remove(key);
5546 } else {
5547 authTokensForAccount.put(key, value);
Fred Quintana56285a62010-12-02 14:20:51 -08005548 }
5549 }
5550
Amith Yamasani04e0d262012-02-14 11:50:53 -08005551 protected String readAuthTokenInternal(UserAccounts accounts, Account account,
5552 String authTokenType) {
5553 synchronized (accounts.cacheLock) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005554 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
Fred Quintana56285a62010-12-02 14:20:51 -08005555 if (authTokensForAccount == null) {
5556 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005557 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
Amith Yamasani04e0d262012-02-14 11:50:53 -08005558 accounts.authTokenCache.put(account, authTokensForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005559 }
5560 return authTokensForAccount.get(authTokenType);
5561 }
5562 }
5563
Simranjit Kohli858511c2016-03-10 18:36:11 +00005564 protected String readUserDataInternalLocked(
5565 UserAccounts accounts, Account account, String key) {
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005566 Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005567 if (userDataForAccount == null) {
5568 // need to populate the cache for this account
Fyodor Kupolov00de49e2016-09-23 13:10:27 -07005569 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
Simranjit Kohli858511c2016-03-10 18:36:11 +00005570 accounts.userDataCache.put(account, userDataForAccount);
Fred Quintana56285a62010-12-02 14:20:51 -08005571 }
Simranjit Kohli858511c2016-03-10 18:36:11 +00005572 return userDataForAccount.get(key);
Fred Quintana56285a62010-12-02 14:20:51 -08005573 }
5574
Kenny Guy07ad8dc2014-09-01 20:56:12 +01005575 private Context getContextForUser(UserHandle user) {
5576 try {
5577 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
5578 } catch (NameNotFoundException e) {
5579 // Default to mContext, not finding the package system is running as is unlikely.
5580 return mContext;
5581 }
5582 }
Sandra Kwan78812282015-11-04 11:19:47 -08005583
5584 private void sendResponse(IAccountManagerResponse response, Bundle result) {
5585 try {
5586 response.onResult(result);
5587 } catch (RemoteException e) {
5588 // if the caller is dead then there is no one to care about remote
5589 // exceptions
5590 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5591 Log.v(TAG, "failure while notifying response", e);
5592 }
5593 }
5594 }
5595
5596 private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
5597 String errorMessage) {
5598 try {
5599 response.onError(errorCode, errorMessage);
5600 } catch (RemoteException e) {
5601 // if the caller is dead then there is no one to care about remote
5602 // exceptions
5603 if (Log.isLoggable(TAG, Log.VERBOSE)) {
5604 Log.v(TAG, "failure while notifying response", e);
5605 }
5606 }
5607 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005608
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005609 private final class AccountManagerInternalImpl extends AccountManagerInternal {
Svet Ganov5d09c992016-09-07 09:57:41 -07005610 private final Object mLock = new Object();
5611
5612 @GuardedBy("mLock")
5613 private AccountManagerBackupHelper mBackupHelper;
5614
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005615 @Override
5616 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
5617 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
5618 if (account == null) {
5619 Slog.w(TAG, "account cannot be null");
5620 return;
5621 }
5622 if (packageName == null) {
5623 Slog.w(TAG, "packageName cannot be null");
5624 return;
5625 }
5626 if (userId < UserHandle.USER_SYSTEM) {
5627 Slog.w(TAG, "user id must be concrete");
5628 return;
5629 }
5630 if (callback == null) {
5631 Slog.w(TAG, "callback cannot be null");
5632 return;
5633 }
5634
Svet Ganovf6d424f12016-09-20 20:18:53 -07005635 if (AccountManagerService.this.hasAccountAccess(account, packageName,
5636 new UserHandle(userId))) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005637 Bundle result = new Bundle();
5638 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
5639 callback.sendResult(result);
5640 return;
5641 }
5642
5643 final int uid;
5644 try {
5645 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
5646 } catch (NameNotFoundException e) {
5647 Slog.e(TAG, "Unknown package " + packageName);
5648 return;
5649 }
5650
5651 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
Svet Ganovf6d424f12016-09-20 20:18:53 -07005652 final UserAccounts userAccounts;
5653 synchronized (mUsers) {
5654 userAccounts = mUsers.get(userId);
5655 }
5656 doNotification(userAccounts, account, null, intent, packageName, userId);
5657 }
5658
5659 @Override
5660 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
5661 // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
5662 mAppPermissionChangeListeners.add(listener);
5663 }
5664
5665 @Override
5666 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
5667 return AccountManagerService.this.hasAccountAccess(account, null, uid);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07005668 }
Svet Ganov5d09c992016-09-07 09:57:41 -07005669
5670 @Override
5671 public byte[] backupAccountAccessPermissions(int userId) {
5672 synchronized (mLock) {
5673 if (mBackupHelper == null) {
5674 mBackupHelper = new AccountManagerBackupHelper(
5675 AccountManagerService.this, this);
5676 }
5677 return mBackupHelper.backupAccountAccessPermissions(userId);
5678 }
5679 }
5680
5681 @Override
5682 public void restoreAccountAccessPermissions(byte[] data, int userId) {
5683 synchronized (mLock) {
5684 if (mBackupHelper == null) {
5685 mBackupHelper = new AccountManagerBackupHelper(
5686 AccountManagerService.this, this);
5687 }
5688 mBackupHelper.restoreAccountAccessPermissions(data, userId);
5689 }
5690 }
Fyodor Kupolov1e8a94b2016-08-09 16:08:59 -07005691 }
Fyodor Kupolovda993802016-09-21 14:47:10 -07005692
5693 @VisibleForTesting
5694 static class Injector {
5695 private final Context mContext;
5696
5697 public Injector(Context context) {
5698 mContext = context;
5699 }
5700
5701 Looper getMessageHandlerLooper() {
5702 ServiceThread serviceThread = new ServiceThread(TAG,
5703 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
5704 serviceThread.start();
5705 return serviceThread.getLooper();
5706 }
5707
5708 Context getContext() {
5709 return mContext;
5710 }
5711
5712 void addLocalService(AccountManagerInternal service) {
5713 LocalServices.addService(AccountManagerInternal.class, service);
5714 }
5715
5716 String getDeDatabaseName(int userId) {
5717 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
5718 AccountsDb.DE_DATABASE_NAME);
5719 return databaseFile.getPath();
5720 }
5721
5722 String getCeDatabaseName(int userId) {
5723 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
5724 AccountsDb.CE_DATABASE_NAME);
5725 return databaseFile.getPath();
5726 }
5727
5728 String getPreNDatabaseName(int userId) {
5729 File systemDir = Environment.getDataSystemDirectory();
5730 File databaseFile = new File(Environment.getUserSystemDirectory(userId),
5731 PRE_N_DATABASE_NAME);
5732 if (userId == 0) {
5733 // Migrate old file, if it exists, to the new location.
5734 // Make sure the new file doesn't already exist. A dummy file could have been
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005735 // accidentally created in the old location,
5736 // causing the new one to become corrupted as well.
Fyodor Kupolovda993802016-09-21 14:47:10 -07005737 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
5738 if (oldFile.exists() && !databaseFile.exists()) {
5739 // Check for use directory; create if it doesn't exist, else renameTo will fail
5740 File userDir = Environment.getUserSystemDirectory(userId);
5741 if (!userDir.exists()) {
5742 if (!userDir.mkdirs()) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005743 throw new IllegalStateException(
5744 "User dir cannot be created: " + userDir);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005745 }
5746 }
5747 if (!oldFile.renameTo(databaseFile)) {
Dmitry Dementyev01985ff2017-01-19 16:03:39 -08005748 throw new IllegalStateException(
5749 "User dir cannot be migrated: " + databaseFile);
Fyodor Kupolovda993802016-09-21 14:47:10 -07005750 }
5751 }
5752 }
5753 return databaseFile.getPath();
5754 }
5755
5756 IAccountAuthenticatorCache getAccountAuthenticatorCache() {
5757 return new AccountAuthenticatorCache(mContext);
5758 }
5759
5760 INotificationManager getNotificationManager() {
5761 return NotificationManager.getService();
5762 }
5763 }
Fred Quintana60307342009-03-24 22:48:12 -07005764}