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
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d440017..ff8cf66 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3430,6 +3430,8 @@
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 @@
}
/** {@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 dd53cbb..d55201f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -36,7 +36,6 @@
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 @@
/** {@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 f68e227..fbf7b26 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -25,6 +25,7 @@
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 @@
}
/** {@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 8a0759f..893eb37 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -824,6 +824,8 @@
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 4d86a92..14c17f3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2530,6 +2530,9 @@
<java-symbol type="string" name="profile_encrypted_message" />
<java-symbol type="drawable" name="ic_user_secure" />
+ <java-symbol type="string" name="android_upgrading_notification_title" />
+ <java-symbol type="string" name="android_upgrading_notification_body" />
+
<java-symbol type="string" name="usb_mtp_launch_notification_title" />
<java-symbol type="string" name="usb_mtp_launch_notification_description" />
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index fc2e95d..ae31438 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 @@
private void updateServicesLocked(UserState userState) {
Map<ComponentName, Service> 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 @@
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 0428ecf..7b9d4456 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 @@
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 @@
}
private void onPackageBroadcastReceived(Intent intent, int userId) {
- if (!mUserManager.isUserUnlocked(userId) ||
+ if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
isProfileWithLockedParent(userId)) {
return;
}
@@ -455,7 +455,7 @@
* 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 @@
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 @@
}
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 @@
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 @@
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 79d16da..a584f70 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1020,7 +1020,7 @@
// 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 @@
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 a3ef6b6b..c912b11 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -256,13 +256,13 @@
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 @@
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 ec05dae..b0581aa 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2816,17 +2816,19 @@
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 @@
@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 a628747..4b0d4be 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -166,7 +166,7 @@
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 @@
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 480da72..96214d6 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 @@
}
private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
- private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
+ private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
@@ -424,7 +424,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 9d7ddc7..21a9f2c 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 @@
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 @@
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 @@
* 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 6622b34..572653b 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 @@
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 cdb68d8..d030d6a 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 @@
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 @@
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 @@
}
}
- // 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 @@
}
// Only keep marching forward if user is actually unlocked
- if (!isUserKeyUnlocked(userId)) return;
+ if (!StorageManager.isUserKeyUnlocked(userId)) return;
- if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) {
- // Remember that we logged in
- mUserManager.onUserLoggedIn(userId);
+ // 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 (!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 @@
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.
* <p>The user will be brought to the foreground, if {@code foreground} parameter is set.
@@ -935,7 +938,7 @@
}
}
- if (!isUserKeyUnlocked(userId)) {
+ if (!StorageManager.isUserKeyUnlocked(userId)) {
final UserInfo userInfo = getUserInfo(userId);
final IMountService mountService = getMountService();
try {
@@ -1321,30 +1324,31 @@
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 4b0eeed..6567965 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 @@
// 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 @@
@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 @@
}
/**
- * 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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 a085370..a2d859b 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 @@
@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 e3e1097..4d91814 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 @@
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 56e2001..93fbe5c 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 @@
}
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 4d02928..f2c995b 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 @@
@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 @@
@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 @@
@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 @@
@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 @@
}
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");
}