Merge "Wire up lifecycle, send unlocked broadcast."
diff --git a/api/current.txt b/api/current.txt
index 73962f8f..fc95ca3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8344,6 +8344,7 @@
field public static final java.lang.String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND";
field public static final java.lang.String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
field public static final java.lang.String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
+ field public static final java.lang.String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
field public static final java.lang.String ACTION_VIEW = "android.intent.action.VIEW";
field public static final java.lang.String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
field public static final deprecated java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
diff --git a/api/system-current.txt b/api/system-current.txt
index c4d99b8..409a7d5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8602,6 +8602,7 @@
field public static final java.lang.String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND";
field public static final java.lang.String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
field public static final java.lang.String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
+ field public static final java.lang.String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
field public static final java.lang.String ACTION_VIEW = "android.intent.action.VIEW";
field public static final java.lang.String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
field public static final deprecated java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
diff --git a/api/test-current.txt b/api/test-current.txt
index 73962f8f..fc95ca3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8344,6 +8344,7 @@
field public static final java.lang.String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND";
field public static final java.lang.String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
field public static final java.lang.String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
+ field public static final java.lang.String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
field public static final java.lang.String ACTION_VIEW = "android.intent.action.VIEW";
field public static final java.lang.String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
field public static final deprecated java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f7aee75..f1a7de8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3084,7 +3084,7 @@
/** {@hide} */
public static final int FLAG_OR_STOPPED = 1 << 0;
/** {@hide} */
- public static final int FLAG_WITH_AMNESIA = 1 << 1;
+ public static final int FLAG_AND_LOCKED = 1 << 1;
/**
* Return whether the given user is actively running. This means that
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4a7cbc7..e25f1d7 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2877,6 +2877,14 @@
"android.intent.action.USER_SWITCHED";
/**
+ * Broadcast Action: Sent when the credential-encrypted private storage has
+ * become unlocked for the target user. This is only sent to registered
+ * receivers, not manifest receivers.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
+
+ /**
* Broadcast sent to the system when a user's information changes. Carries an extra
* {@link #EXTRA_USER_HANDLE} to indicate which user's information changed.
* This is only sent to registered receivers, not manifest receivers. It is sent to all users.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 1996e0f..65e5945 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -487,6 +487,13 @@
public static final int PRIVATE_FLAG_AUTOPLAY = 1 << 7;
/**
+ * When set, at least one component inside this application is encryption aware.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE = 1 << 8;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
@@ -1054,6 +1061,11 @@
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE) != 0;
}
+ /** @hide */
+ public boolean isPartiallyEncryptionAware() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE) != 0;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6fe1efd..b9a42eb 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -59,7 +59,7 @@
* {@hide}
*/
interface IPackageManager {
- boolean isPackageFrozen(String packageName);
+ void checkPackageStartable(String packageName, int userId);
boolean isPackageAvailable(String packageName, int userId);
PackageInfo getPackageInfo(String packageName, int flags, int userId);
int getPackageUid(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 838da37..17af944 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3262,6 +3262,11 @@
owner.applicationInfo.isEncryptionAware());
}
+ if (a.info.encryptionAware) {
+ owner.applicationInfo.privateFlags |=
+ ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
+ }
+
sa.recycle();
if (receiver && (owner.applicationInfo.privateFlags
@@ -3663,6 +3668,10 @@
p.info.encryptionAware = sa.getBoolean(
R.styleable.AndroidManifestProvider_encryptionAware,
owner.applicationInfo.isEncryptionAware());
+ if (p.info.encryptionAware) {
+ owner.applicationInfo.privateFlags |=
+ ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
+ }
sa.recycle();
@@ -3947,6 +3956,10 @@
s.info.encryptionAware = sa.getBoolean(
R.styleable.AndroidManifestService_encryptionAware,
owner.applicationInfo.isEncryptionAware());
+ if (s.info.encryptionAware) {
+ owner.applicationInfo.privateFlags |=
+ ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
+ }
sa.recycle();
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index da81528..d6c6f13 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
import android.app.trust.IStrongAuthTracker;
@@ -388,6 +390,13 @@
}
}
+ private void unlockUser(int userId, byte[] token) {
+ try {
+ ActivityManagerNative.getDefault().unlockUser(userId, token);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
private byte[] getCurrentHandle(int userId) {
CredentialHash credential;
@@ -612,6 +621,7 @@
byte[] hash = credentialUtil.toHash(credential, userId);
if (Arrays.equals(hash, storedHash.hash)) {
unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
+ unlockUser(userId, null);
// migrate credential to GateKeeper
credentialUtil.setCredential(credential, null, userId);
if (!hasChallenge) {
@@ -664,6 +674,7 @@
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
// credential has matched
unlockKeystore(credential, userId);
+ unlockUser(userId, null);
if (shouldReEnroll) {
credentialUtil.setCredential(credential, credential, userId);
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index a32bb2f..bd43a71 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -781,6 +781,7 @@
}
private void handleSystemReady() {
+ initIfReadyAndConnected();
resetIfReadyAndConnected();
// Start scheduling nominally-daily fstrim operations
@@ -828,6 +829,22 @@
mVolumes.put(internal.id, internal);
}
+ private void initIfReadyAndConnected() {
+ Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
+ + ", mDaemonConnected=" + mDaemonConnected);
+ if (mSystemReady && mDaemonConnected && StorageManager.isFileBasedEncryptionEnabled()) {
+ final List<UserInfo> users = mContext.getSystemService(UserManager.class)
+ .getUsers();
+ for (UserInfo user : users) {
+ try {
+ mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
+ } catch (NativeDaemonConnectorException e) {
+ Slog.w(TAG, "Failed to init vold", e);
+ }
+ }
+ }
+ }
+
private void resetIfReadyAndConnected() {
Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
+ ", mDaemonConnected=" + mDaemonConnected);
@@ -928,6 +945,7 @@
}
private void handleDaemonConnected() {
+ initIfReadyAndConnected();
resetIfReadyAndConnected();
/*
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 557b386..99470c8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3356,10 +3356,8 @@
try {
try {
- if (AppGlobals.getPackageManager().isPackageFrozen(app.info.packageName)) {
- // This is caught below as if we had failed to fork zygote
- throw new RuntimeException("Package " + app.info.packageName + " is frozen!");
- }
+ final int userId = UserHandle.getUserId(app.uid);
+ AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b30905e..9c29149 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -624,6 +624,23 @@
throw new SecurityException(msg);
}
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ return unlockUserCleared(userId, token);
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ boolean unlockUserCleared(final int userId, byte[] token) {
+ synchronized (mService) {
+ final UserState uss = mStartedUsers.get(userId);
+ if (uss.unlocked) {
+ // Bail early when already unlocked
+ return true;
+ }
+ }
+
final UserInfo userInfo = getUserInfo(userId);
final IMountService mountService = IMountService.Stub
.asInterface(ServiceManager.getService("mount"));
@@ -631,7 +648,7 @@
mountService.unlockUserKey(userId, userInfo.serialNumber, token);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to unlock: " + e.getMessage());
- throw e.rethrowAsRuntimeException();
+ return false;
}
synchronized (mService) {
@@ -639,6 +656,11 @@
updateUserUnlockedState(uss);
}
+ final Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+ mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, userId);
+
return true;
}
@@ -1011,7 +1033,7 @@
if ((flags & ActivityManager.FLAG_OR_STOPPED) != 0) {
return true;
}
- if ((flags & ActivityManager.FLAG_WITH_AMNESIA) != 0) {
+ if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0) {
// If user is currently locked, we fall through to default "running"
// behavior below
if (state.unlocked) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4bc79cb..c7d1171 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2800,15 +2800,24 @@
}
@Override
- public boolean isPackageFrozen(String packageName) {
+ public void checkPackageStartable(String packageName, int userId) {
+ final boolean userKeyUnlocked = isUserKeyUnlocked(userId);
+
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
- return ps.frozen;
+ if (ps == null) {
+ throw new SecurityException("Package " + packageName + " was not found!");
+ }
+
+ if (ps.frozen) {
+ throw new SecurityException("Package " + packageName + " is currently frozen!");
+ }
+
+ if (!userKeyUnlocked && !(ps.pkg.applicationInfo.isEncryptionAware()
+ || ps.pkg.applicationInfo.isPartiallyEncryptionAware())) {
+ throw new SecurityException("Package " + packageName + " is not encryption aware!");
}
}
- Slog.w(TAG, "Package " + packageName + " is missing; assuming frozen");
- return true;
}
@Override
@@ -3143,29 +3152,36 @@
}
/**
- * Augment the given flags depending on current user running state. This is
- * purposefully done before acquiring {@link #mPackages} lock.
+ * Return if the user key is currently unlocked.
*/
- private int augmentFlagsForUser(int flags, int userId) {
+ private boolean isUserKeyUnlocked(int userId) {
if (StorageManager.isFileBasedEncryptionEnabled()) {
final IMountService mount = IMountService.Stub
.asInterface(ServiceManager.getService("mount"));
if (mount == null) {
- // We must be early in boot, so the best we can do is assume the
- // user is fully running.
- Slog.w(TAG, "Early during boot, assuming not encrypted");
- return flags;
+ Slog.w(TAG, "Early during boot, assuming locked");
+ return false;
}
final long token = Binder.clearCallingIdentity();
try {
- if (!mount.isUserKeyUnlocked(userId)) {
- flags |= PackageManager.MATCH_ENCRYPTION_AWARE_ONLY;
- }
+ return mount.isUserKeyUnlocked(userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} finally {
Binder.restoreCallingIdentity(token);
}
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Augment the given flags depending on current user running state. This is
+ * purposefully done before acquiring {@link #mPackages} lock.
+ */
+ private int augmentFlagsForUser(int flags, int userId) {
+ if (!isUserKeyUnlocked(userId)) {
+ flags |= PackageManager.MATCH_ENCRYPTION_AWARE_ONLY;
}
return flags;
}