From ce18c8167766f92856f94a8e88e19de4698960e6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 27 Apr 2016 16:00:41 -0600 Subject: [PATCH] Introduce "unlocking" vs "unlocked" nuance. There is a narrow window of time during user unlock where we're reconciling user storage and dispatching the "unlock" status to various internal system services. While in this "unlocking" state, apps need to be told that the user still isn't actually "unlocked" so they don't try making calls to AccountManager, etc. The majority of internal services are interested in merging together both the "unlocking" and "unlocked" state, so update them. Clarify naming in AccountManagerService to make it clear that a local list is being used, which mirrors the naming in MountService. To match UX/PM requested behavior, move PRE_BOOT_COMPLETED dispatch after the user is unlocked, but block BOOT_COMPLETED dispatch until after all PRE_BOOT receivers are finished to avoid ANRs. Bug: 28040947, 28164677 Change-Id: I57af2351633d9159f4483f19657ce0b62118d1ce --- core/java/android/app/ActivityManager.java | 22 +-- core/java/android/os/UserManager.java | 26 +++- core/java/android/os/storage/StorageManager.java | 16 ++- core/java/android/provider/CallLog.java | 2 + core/res/res/values/symbols.xml | 3 + .../accessibility/AccessibilityManagerService.java | 6 +- .../server/appwidget/AppWidgetServiceImpl.java | 14 +- .../android/server/InputMethodManagerService.java | 4 +- .../com/android/server/LockSettingsService.java | 6 +- .../core/java/com/android/server/MountService.java | 30 ++-- .../android/server/TextServicesManagerService.java | 4 +- .../server/accounts/AccountManagerService.java | 31 ++-- .../android/server/am/ActivityManagerService.java | 18 +-- .../com/android/server/am/ActivityStarter.java | 4 +- .../java/com/android/server/am/UserController.java | 160 +++++++++++---------- .../android/server/pm/PackageManagerService.java | 44 +----- .../com/android/server/pm/UserManagerService.java | 2 +- .../server/search/SearchManagerService.java | 2 +- .../devicepolicy/DevicePolicyManagerService.java | 2 + .../android/server/print/PrintManagerService.java | 10 +- 20 files changed, 193 insertions(+), 213 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d4400171ea89..ff8cf66770eb 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -3430,6 +3430,8 @@ public class ActivityManager { public static final int FLAG_AND_LOCKED = 1 << 1; /** {@hide} */ public static final int FLAG_AND_UNLOCKED = 1 << 2; + /** {@hide} */ + public static final int FLAG_AND_UNLOCKING_OR_UNLOCKED = 1 << 3; /** * Return whether the given user is actively running. This means that @@ -3449,26 +3451,6 @@ public class ActivityManager { } /** {@hide} */ - public boolean isUserRunningAndLocked(int userId) { - try { - return ActivityManagerNative.getDefault().isUserRunning(userId, - ActivityManager.FLAG_AND_LOCKED); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - public boolean isUserRunningAndUnlocked(int userId) { - try { - return ActivityManagerNative.getDefault().isUserRunning(userId, - ActivityManager.FLAG_AND_UNLOCKED); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ public boolean isVrModePackageEnabled(ComponentName component) { try { return ActivityManagerNative.getDefault().isVrModePackageEnabled(component); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index dd53cbb41c3e..d55201f709e9 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -36,7 +36,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.os.storage.StorageManager; import android.provider.Settings; import android.telephony.TelephonyManager; import android.view.WindowManager.LayoutParams; @@ -984,10 +983,27 @@ public class UserManager { /** {@hide} */ public boolean isUserUnlocked(@UserIdInt int userId) { - // TODO: eventually pivot this back to look at ActivityManager state, - // but there is race where we can start a non-encryption-aware launcher - // before that lifecycle has entered the running unlocked state. - return mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userId); + try { + return ActivityManagerNative.getDefault().isUserRunning(userId, + ActivityManager.FLAG_AND_UNLOCKED); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** {@hide} */ + public boolean isUserUnlockingOrUnlocked(UserHandle user) { + return isUserUnlockingOrUnlocked(user.getIdentifier()); + } + + /** {@hide} */ + public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) { + try { + return ActivityManagerNative.getDefault().isUserRunning(userId, + ActivityManager.FLAG_AND_UNLOCKING_OR_UNLOCKED); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } } /** diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index f68e227a32a3..fbf7b266330b 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -25,6 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.IPackageMoveObserver; import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; @@ -1062,11 +1063,20 @@ public class StorageManager { } /** {@hide} */ - public boolean isUserKeyUnlocked(int userId) { + public static boolean isUserKeyUnlocked(int userId) { + final IMountService mount = IMountService.Stub + .asInterface(ServiceManager.getService("mount")); + if (mount == null) { + Slog.w(TAG, "Early during boot, assuming locked"); + return false; + } + final long token = Binder.clearCallingIdentity(); try { - return mMountService.isUserKeyUnlocked(userId); + return mount.isUserKeyUnlocked(userId); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); + } finally { + Binder.restoreCallingIdentity(token); } } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 8a0759fbdb46..893eb3701df4 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -824,6 +824,8 @@ public class CallLog { UserHandle user, ContentValues values) { final ContentResolver resolver = context.getContentResolver(); + // Since we're doing this operation on behalf of an app, we only + // want to use the actual "unlocked" state. final Uri uri = ContentProvider.maybeAddUserId( userManager.isUserUnlocked(user) ? CONTENT_URI : SHADOW_CONTENT_URI, user.getIdentifier()); diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4d86a9252ced..14c17f37e35a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2530,6 +2530,9 @@ + + + diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index fc2e95dc7ca5..ae314386bc7f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1245,8 +1245,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private void updateServicesLocked(UserState userState) { Map componentNameToServiceMap = userState.mComponentNameToServiceMap; - boolean isUnlocked = mContext.getSystemService(UserManager.class) - .isUserUnlocked(userState.mUserId); + boolean isUnlockingOrUnlocked = mContext.getSystemService(UserManager.class) + .isUserUnlockingOrUnlocked(userState.mUserId); for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); @@ -1256,7 +1256,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Service service = componentNameToServiceMap.get(componentName); // Ignore non-encryption-aware services until user is unlocked - if (!isUnlocked && !installedService.isDirectBootAware()) { + if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) { Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName); continue; } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 0428ecfeb779..7b9d44560563 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -335,7 +335,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Provider provider = installedProviders.get(i); final int userId = provider.getUserId(); - if (!mUserManager.isUserUnlocked(userId) || + if (!mUserManager.isUserUnlockingOrUnlocked(userId) || isProfileWithLockedParent(userId)) { continue; } @@ -369,7 +369,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void onPackageBroadcastReceived(Intent intent, int userId) { - if (!mUserManager.isUserUnlocked(userId) || + if (!mUserManager.isUserUnlockingOrUnlocked(userId) || isProfileWithLockedParent(userId)) { return; } @@ -455,7 +455,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku * userId must be the group parent. */ private void reloadWidgetsMaskedStateForGroup(int userId) { - if (!mUserManager.isUserUnlocked(userId)) { + if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { return; } synchronized (mLock) { @@ -472,7 +472,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku try { UserInfo user = mUserManager.getUserInfo(userId); - boolean lockedProfile = !mUserManager.isUserUnlocked(userId); + boolean lockedProfile = !mUserManager.isUserUnlockingOrUnlocked(userId); boolean quietProfile = user.isQuietModeEnabled(); final int N = mProviders.size(); for (int i = 0; i < N; i++) { @@ -656,7 +656,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void ensureGroupStateLoadedLocked(int userId) { - if (!mUserManager.isUserUnlocked(userId)) { + if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { throw new IllegalStateException( "User " + userId + " must be unlocked for widgets to be available"); } @@ -3363,7 +3363,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (userInfo != null && userInfo.isManagedProfile()) { UserInfo parentInfo = mUserManager.getProfileParent(userId); if (parentInfo != null - && !mUserManager.isUserUnlocked(parentInfo.getUserHandle())) { + && !mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) { return true; } } @@ -3378,7 +3378,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (userInfo != null && userInfo.isManagedProfile()) { UserInfo parentInfo = mUserManager.getProfileParent(userId); if (parentInfo != null - && mUserManager.isUserUnlocked(parentInfo.getUserHandle())) { + && mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) { return true; } } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 79d16da00ee7..a584f707f9a9 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -1020,7 +1020,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // If the system is not ready or the device is not yed unlocked by the user, then we use // copy-on-write settings. final boolean useCopyOnWriteSettings = - !mSystemReady || !mUserManager.isUserUnlocked(newUserId); + !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(newUserId); mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings); updateCurrentProfileIds(); // InputMethodFileManager should be reset when the user is changed @@ -1077,7 +1077,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSystemReady = true; final int currentUserId = mSettings.getCurrentUserId(); mSettings.switchCurrentUser(currentUserId, - !mUserManager.isUserUnlocked(currentUserId)); + !mUserManager.isUserUnlockingOrUnlocked(currentUserId)); mKeyguardManager = mContext.getSystemService(KeyguardManager.class); mNotificationManager = mContext.getSystemService(NotificationManager.class); mStatusBar = statusBar; diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index a3ef6b6b53fa..c912b11250dd 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -256,13 +256,13 @@ public class LockSettingsService extends ILockSettings.Stub { for (int i = 0; i < users.size(); i++) { UserInfo user = users.get(i); UserHandle userHandle = user.getUserHandle(); - if (!mUserManager.isUserUnlocked(userHandle)) { + if (!mUserManager.isUserUnlockingOrUnlocked(userHandle)) { if (!user.isManagedProfile()) { showEncryptionNotification(userHandle); } else { UserInfo parent = mUserManager.getProfileParent(user.id); if (parent != null && - mUserManager.isUserUnlocked(parent.getUserHandle()) && + mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) && !mUserManager.isQuietModeEnabled(userHandle)) { // Only show notifications for managed profiles once their parent // user is unlocked. @@ -350,7 +350,7 @@ public class LockSettingsService extends ILockSettings.Stub { UserInfo profile = profiles.get(i); if (profile.isManagedProfile()) { UserHandle userHandle = profile.getUserHandle(); - if (!mUserManager.isUserUnlocked(userHandle) && + if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) && !mUserManager.isQuietModeEnabled(userHandle)) { showEncryptionNotificationForProfile(userHandle); } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index ec05dae68a85..b0581aa331fb 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -2816,17 +2816,19 @@ class MountService extends IMountService.Stub enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); waitForReady(); - // When a user has secure lock screen, require a challenge token to - // actually unlock. This check is mostly in place for emulation mode. - if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) { - throw new IllegalStateException("Token required to unlock secure user " + userId); - } + if (StorageManager.isFileEncryptedNativeOrEmulated()) { + // When a user has secure lock screen, require a challenge token to + // actually unlock. This check is mostly in place for emulation mode. + if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) { + throw new IllegalStateException("Token required to unlock secure user " + userId); + } - try { - mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber, - encodeBytes(token), encodeBytes(secret)); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); + try { + mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber, + encodeBytes(token), encodeBytes(secret)); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } } synchronized (mLock) { @@ -2852,12 +2854,8 @@ class MountService extends IMountService.Stub @Override public boolean isUserKeyUnlocked(int userId) { - if (StorageManager.isFileEncryptedNativeOrEmulated()) { - synchronized (mLock) { - return ArrayUtils.contains(mLocalUnlockedUsers, userId); - } - } else { - return true; + synchronized (mLock) { + return ArrayUtils.contains(mLocalUnlockedUsers, userId); } } diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java index a62874779c04..4b0d4be11b14 100644 --- a/services/core/java/com/android/server/TextServicesManagerService.java +++ b/services/core/java/com/android/server/TextServicesManagerService.java @@ -166,7 +166,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { mMonitor = new TextServicesMonitor(); mMonitor.register(context, null, true); final boolean useCopyOnWriteSettings = - !mSystemReady || !mUserManager.isUserUnlocked(userId); + !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(userId); mSettings = new TextServicesSettings(context.getContentResolver(), userId, useCopyOnWriteSettings); @@ -176,7 +176,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { private void resetInternalState(@UserIdInt int userId) { final boolean useCopyOnWriteSettings = - !mSystemReady || !mUserManager.isUserUnlocked(userId); + !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(userId); mSettings.switchCurrentUser(userId, useCopyOnWriteSettings); updateCurrentProfileIds(); unbindServiceLocked(); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 480da72d9579..96214d6b1a08 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -304,7 +304,7 @@ public class AccountManagerService } private final SparseArray mUsers = new SparseArray<>(); - private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray(); + private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray(); private static AtomicReference sThis = new AtomicReference<>(); private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{}; @@ -424,7 +424,7 @@ public class AccountManagerService if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "validateAccountsInternal " + accounts.userId + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached() - + " userLocked=" + mUnlockedUsers.get(accounts.userId)); + + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId)); } if (invalidateAuthenticatorCache) { mAuthenticatorCache.invalidateCache(accounts.userId); @@ -575,7 +575,7 @@ public class AccountManagerService validateAccounts = true; } // open CE database if necessary - if (!accounts.openHelper.isCeDatabaseAttached() && mUnlockedUsers.get(userId)) { + if (!accounts.openHelper.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) { Log.i(TAG, "User " + userId + " is unlocked - opening CE database"); synchronized (accounts.cacheLock) { File preNDatabaseFile = new File(getPreNDatabaseName(userId)); @@ -648,8 +648,8 @@ public class AccountManagerService synchronized (mUsers) { accounts = mUsers.get(userId); mUsers.remove(userId); - userUnlocked = mUnlockedUsers.get(userId); - mUnlockedUsers.delete(userId); + userUnlocked = mLocalUnlockedUsers.get(userId); + mLocalUnlockedUsers.delete(userId); } if (accounts != null) { synchronized (accounts.cacheLock) { @@ -686,7 +686,7 @@ public class AccountManagerService Log.v(TAG, "onUserUnlocked " + userId); } synchronized (mUsers) { - mUnlockedUsers.put(userId, true); + mLocalUnlockedUsers.put(userId, true); } if (userId < 1) return; syncSharedAccounts(userId); @@ -746,7 +746,7 @@ public class AccountManagerService if (account == null) { return null; } - if (!isUserUnlocked(accounts.userId)) { + if (!isLocalUnlockedUser(accounts.userId)) { Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked"); return null; } @@ -828,7 +828,7 @@ public class AccountManagerService account.type); throw new SecurityException(msg); } - if (!isUserUnlocked(userId)) { + if (!isLocalUnlockedUser(userId)) { Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid); return null; } @@ -1109,7 +1109,7 @@ public class AccountManagerService if (account == null) { return false; } - if (!isUserUnlocked(accounts.userId)) { + if (!isLocalUnlockedUser(accounts.userId)) { Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId + " is locked. callingUid=" + callingUid); return false; @@ -1176,9 +1176,9 @@ public class AccountManagerService return true; } - private boolean isUserUnlocked(int userId) { + private boolean isLocalUnlockedUser(int userId) { synchronized (mUsers) { - return mUnlockedUsers.get(userId); + return mLocalUnlockedUsers.get(userId); } } @@ -1193,7 +1193,7 @@ public class AccountManagerService for (UserInfo user : users) { if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) { addSharedAccountAsUser(account, user.id); - if (getUserManager().isUserUnlocked(user.id)) { + if (isLocalUnlockedUser(user.id)) { mMessageHandler.sendMessage(mMessageHandler.obtainMessage( MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account)); } @@ -1597,7 +1597,7 @@ public class AccountManagerService private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) { int deleted; - boolean userUnlocked = isUserUnlocked(accounts.userId); + boolean userUnlocked = isLocalUnlockedUser(accounts.userId); if (!userUnlocked) { Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId + " is still locked. CE data will be removed later"); @@ -1792,7 +1792,7 @@ public class AccountManagerService account.type); throw new SecurityException(msg); } - if (!isUserUnlocked(userId)) { + if (!isLocalUnlockedUser(userId)) { Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid " + callingUid); return null; @@ -4037,8 +4037,7 @@ public class AccountManagerService return false; } - final ActivityManager am = mContext.getSystemService(ActivityManager.class); - if (am.isUserRunningAndLocked(mAccounts.userId) + if (!isLocalUnlockedUser(mAccounts.userId) && !authenticatorInfo.componentInfo.directBootAware) { Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName + " which isn't encryption aware"); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9d7ddc7b96c1..21a9f2c9735c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1946,9 +1946,7 @@ public final class ActivityManagerService extends ActivityManagerNative startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE); } installEncryptionUnawareProviders(userId); - if (msg.obj instanceof ProgressReporter) { - ((ProgressReporter) msg.obj).finish(); - } + mUserController.finishUserUnlocked((UserState) msg.obj); break; } case SYSTEM_USER_CURRENT_MSG: { @@ -6304,7 +6302,11 @@ public final class ActivityManagerService extends ActivityManagerNative app.debugging = false; app.cached = false; app.killedByAm = false; - app.unlocked = mContext.getSystemService(UserManager.class).isUserUnlocked(app.userId); + + // We carefully use the same state that PackageManager uses for + // filtering, since we use this flag to decide if we need to install + // providers when user is unlocked later + app.unlocked = StorageManager.isUserKeyUnlocked(app.userId); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); @@ -11024,14 +11026,6 @@ public final class ActivityManagerService extends ActivityManagerNative * belonging to any running apps. */ private void installEncryptionUnawareProviders(int userId) { - if (!StorageManager.isFileEncryptedNativeOrEmulated()) { - // TODO: eventually pivot this back to look at current user state, - // similar to the comment in UserManager.isUserUnlocked(), but for - // now, if we started apps when "unlocked" then unaware providers - // have already been spun up. - return; - } - // We're only interested in providers that are encryption unaware, and // we don't care about uninstalled apps, since there's no way they're // running at this point. diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 6622b34c1106..572653b9f890 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -683,8 +683,8 @@ class ActivityStarter { Binder.restoreCallingIdentity(token); } if (parent != null - && userManager.isUserUnlocked(parent.getUserHandle()) - && !userManager.isUserUnlocked(userInfo.getUserHandle())) { + && userManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) + && !userManager.isUserUnlockingOrUnlocked(userInfo.getUserHandle())) { rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index cdb68d8aeff6..d030d6ad04d9 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -270,7 +270,7 @@ final class UserController { if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; // Only keep marching forward if user is actually unlocked - if (!isUserKeyUnlocked(userId)) return; + if (!StorageManager.isUserKeyUnlocked(userId)) return; if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) { uss.mUnlockProgress.start(); @@ -281,9 +281,29 @@ final class UserController { mUserManager.onBeforeUnlockUser(userId); uss.mUnlockProgress.setProgress(20); - // Dispatch unlocked to system services - mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss.mUnlockProgress) + // Dispatch unlocked to system services; when fully dispatched, + // that calls through to the next "unlocked" phase + mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) .sendToTarget(); + } + } + } + + /** + * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to + * {@link UserState#STATE_RUNNING_UNLOCKED}. + */ + void finishUserUnlocked(final UserState uss) { + final int userId = uss.mHandle.getIdentifier(); + synchronized (mService) { + // Bail if we ended up with a stale user + if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; + + // Only keep marching forward if user is actually unlocked + if (!StorageManager.isUserKeyUnlocked(userId)) return; + + if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) { + uss.mUnlockProgress.finish(); // Dispatch unlocked to external apps final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED); @@ -310,27 +330,25 @@ final class UserController { } } - // Send PRE_BOOT broadcasts if fingerprint changed + // Send PRE_BOOT broadcasts if user fingerprint changed; we + // purposefully block sending BOOT_COMPLETED until after all + // PRE_BOOT receivers are finished to avoid ANR'ing apps final UserInfo info = getUserInfo(userId); if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) { new PreBootBroadcaster(mService, userId, null) { @Override public void onFinished() { - finishUserUnlocked(uss); + finishUserUnlockedCompleted(uss); } }.sendNext(); } else { - finishUserUnlocked(uss); + finishUserUnlockedCompleted(uss); } } } } - /** - * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to - * {@link UserState#STATE_RUNNING_UNLOCKED}. - */ - private void finishUserUnlocked(UserState uss) { + private void finishUserUnlockedCompleted(UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user @@ -341,39 +359,38 @@ final class UserController { } // Only keep marching forward if user is actually unlocked - if (!isUserKeyUnlocked(userId)) return; - - if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) { - // Remember that we logged in - mUserManager.onUserLoggedIn(userId); - - if (!userInfo.isInitialized()) { - if (userId != UserHandle.USER_SYSTEM) { - Slog.d(TAG, "Initializing user #" + userId); - Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - mService.broadcastIntentLocked(null, null, intent, null, - new IIntentReceiver.Stub() { - @Override - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean ordered, - boolean sticky, int sendingUser) { - // Note: performReceive is called with mService lock held - getUserManager().makeInitialized(userInfo.id); - } - }, 0, null, null, null, AppOpsManager.OP_NONE, - null, true, false, MY_PID, SYSTEM_UID, userId); - } + if (!StorageManager.isUserKeyUnlocked(userId)) return; + + // Remember that we logged in + mUserManager.onUserLoggedIn(userId); + + if (!userInfo.isInitialized()) { + if (userId != UserHandle.USER_SYSTEM) { + Slog.d(TAG, "Initializing user #" + userId); + Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + mService.broadcastIntentLocked(null, null, intent, null, + new IIntentReceiver.Stub() { + @Override + public void performReceive(Intent intent, int resultCode, + String data, Bundle extras, boolean ordered, + boolean sticky, int sendingUser) { + // Note: performReceive is called with mService lock held + getUserManager().makeInitialized(userInfo.id); + } + }, 0, null, null, null, AppOpsManager.OP_NONE, + null, true, false, MY_PID, SYSTEM_UID, userId); } - Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId); - final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); - bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT - | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null, - new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, - AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); } + + Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId); + final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); + bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT + | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null, + new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, + AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); } } @@ -680,20 +697,6 @@ final class UserController { return IMountService.Stub.asInterface(ServiceManager.getService("mount")); } - private boolean isUserKeyUnlocked(int userId) { - final IMountService mountService = getMountService(); - if (mountService != null) { - try { - return mountService.isUserKeyUnlocked(userId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } else { - Slog.w(TAG, "Mount service not published; guessing locked state based on property"); - return !StorageManager.isFileEncryptedNativeOrEmulated(); - } - } - /** * Start user, if its not already running. *

The user will be brought to the foreground, if {@code foreground} parameter is set. @@ -935,7 +938,7 @@ final class UserController { } } - if (!isUserKeyUnlocked(userId)) { + if (!StorageManager.isUserKeyUnlocked(userId)) { final UserInfo userInfo = getUserInfo(userId); final IMountService mountService = getMountService(); try { @@ -1321,30 +1324,31 @@ final class UserController { if ((flags & ActivityManager.FLAG_OR_STOPPED) != 0) { return true; } - - final boolean unlocked; - switch (state.state) { - case UserState.STATE_STOPPING: - case UserState.STATE_SHUTDOWN: - default: - return false; - - case UserState.STATE_BOOTING: - case UserState.STATE_RUNNING_LOCKED: - unlocked = false; - break; - - case UserState.STATE_RUNNING_UNLOCKING: - case UserState.STATE_RUNNING_UNLOCKED: - unlocked = true; - break; - } - if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0) { - return !unlocked; + switch (state.state) { + case UserState.STATE_BOOTING: + case UserState.STATE_RUNNING_LOCKED: + return true; + default: + return false; + } + } + if ((flags & ActivityManager.FLAG_AND_UNLOCKING_OR_UNLOCKED) != 0) { + switch (state.state) { + case UserState.STATE_RUNNING_UNLOCKING: + case UserState.STATE_RUNNING_UNLOCKED: + return true; + default: + return false; + } } if ((flags & ActivityManager.FLAG_AND_UNLOCKED) != 0) { - return unlocked; + switch (state.state) { + case UserState.STATE_RUNNING_UNLOCKED: + return true; + default: + return false; + } } // One way or another, we're running! diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4b0eeedbe125..65679653e521 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2662,14 +2662,8 @@ public class PackageManagerService extends IPackageManager.Stub { // Prepare storage for system user really early during boot, // since core system apps like SettingsProvider and SystemUI // can't wait for user to start - final int storageFlags; - if (StorageManager.isFileEncryptedNativeOrEmulated()) { - storageFlags = StorageManager.FLAG_STORAGE_DE; - } else { - storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; - } reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, - storageFlags); + StorageManager.FLAG_STORAGE_DE); // If this is first boot after an OTA, and a normal boot, then // we need to clear code cache directories. @@ -3100,7 +3094,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void checkPackageStartable(String packageName, int userId) { - final boolean userKeyUnlocked = isUserKeyUnlocked(userId); + final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId); synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -3451,30 +3445,6 @@ public class PackageManagerService extends IPackageManager.Stub { } /** - * Return if the user key is currently unlocked. - */ - private boolean isUserKeyUnlocked(int userId) { - if (StorageManager.isFileEncryptedNativeOrEmulated()) { - final IMountService mount = IMountService.Stub - .asInterface(ServiceManager.getService("mount")); - if (mount == null) { - Slog.w(TAG, "Early during boot, assuming locked"); - return false; - } - final long token = Binder.clearCallingIdentity(); - try { - return mount.isUserKeyUnlocked(userId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } finally { - Binder.restoreCallingIdentity(token); - } - } else { - return true; - } - } - - /** * Update given flags based on encryption status of current user. */ private int updateFlags(int flags, int userId) { @@ -3485,7 +3455,7 @@ public class PackageManagerService extends IPackageManager.Stub { // give them what they want } else { // Caller expressed no opinion, so match based on user state - if (isUserKeyUnlocked(userId)) { + if (StorageManager.isUserKeyUnlocked(userId)) { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; } else { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE; @@ -16046,7 +16016,7 @@ public class PackageManagerService extends IPackageManager.Stub { final UserManager um = mContext.getSystemService(UserManager.class); final int flags; - if (um.isUserUnlocked(userId)) { + if (um.isUserUnlockingOrUnlocked(userId)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (um.isUserRunning(userId)) { flags = StorageManager.FLAG_STORAGE_DE; @@ -18730,7 +18700,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); final UserManager um = mContext.getSystemService(UserManager.class); for (UserInfo user : um.getUsers()) { final int flags; - if (um.isUserUnlocked(user.id)) { + if (um.isUserUnlockingOrUnlocked(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (um.isUserRunning(user.id)) { flags = StorageManager.FLAG_STORAGE_DE; @@ -19044,7 +19014,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // First look for stale data that doesn't belong, and check if things // have changed since we did our last restorecon if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { - if (!isUserKeyUnlocked(userId)) { + if (!StorageManager.isUserKeyUnlocked(userId)) { throw new RuntimeException( "Yikes, someone asked us to reconcile CE storage while " + userId + " was still locked; this would have caused massive data loss!"); @@ -19152,7 +19122,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); final UserManager um = mContext.getSystemService(UserManager.class); for (UserInfo user : um.getUsers()) { final int flags; - if (um.isUserUnlocked(user.id)) { + if (um.isUserUnlockingOrUnlocked(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (um.isUserRunning(user.id)) { flags = StorageManager.FLAG_STORAGE_DE; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index a085370b7164..a2d859b79d30 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -692,7 +692,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) { final int credentialOwnerUserId = getCredentialOwnerProfile(userHandle); - if (mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userHandle) + if (StorageManager.isUserKeyUnlocked(userHandle) || !mLockPatternUtils.isSecure(credentialOwnerUserId)) { // if the user is already unlocked, no need to show a profile challenge setQuietModeEnabled(userHandle, false); diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java index e3e1097cd04d..4d91814af44a 100644 --- a/services/core/java/com/android/server/search/SearchManagerService.java +++ b/services/core/java/com/android/server/search/SearchManagerService.java @@ -112,7 +112,7 @@ public class SearchManagerService extends ISearchManager.Stub { if (um.getUserInfo(userId) == null) { throw new IllegalStateException("User " + userId + " doesn't exist"); } - if (!um.isUserUnlocked(userId)) { + if (!um.isUserUnlockingOrUnlocked(userId)) { throw new IllegalStateException("User " + userId + " isn't unlocked"); } } finally { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 56e2001872e1..93fbe5cd7e7a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6224,6 +6224,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void enforceUserUnlocked(int userId) { + // Since we're doing this operation on behalf of an app, we only + // want to use the actual "unlocked" state. Preconditions.checkState(mUserManager.isUserUnlocked(userId), "User must be running and unlocked"); } diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 4d02928920c6..f2c995b2fc64 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -727,7 +727,7 @@ public final class PrintManagerService extends SystemService { @Override public void onPackageModified(String packageName) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false); synchronized (mLock) { @@ -742,7 +742,7 @@ public final class PrintManagerService extends SystemService { @Override public void onPackageRemoved(String packageName, int uid) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false); synchronized (mLock) { @@ -757,7 +757,7 @@ public final class PrintManagerService extends SystemService { @Override public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, int uid, boolean doit) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return false; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return false; synchronized (mLock) { // A background user/profile's print jobs are running but there is // no UI shown. Hence, if the packages of such a user change we need @@ -795,7 +795,7 @@ public final class PrintManagerService extends SystemService { @Override public void onPackageAdded(String packageName, int uid) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; synchronized (mLock) { if (hasPrintService(packageName)) { UserState userState = getOrCreateUserStateLocked(getChangingUserId(), @@ -812,7 +812,7 @@ public final class PrintManagerService extends SystemService { } private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority) { - if (!mUserManager.isUserUnlocked(userId)) { + if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { throw new IllegalStateException( "User " + userId + " must be unlocked for printing to be available"); } -- 2.11.0