Mount storage after unlock, fix leaving emulation.

Delay mounting of storage devices until after the user is unlocked,
which means any emulated storage areas will be ready for use.  Track
separate per-user unlocked states for local versus system lifecycle
state.

Switch to explicitly lock or unlock user keys during boot of a
device without native FBE support.  This allows us to recover when
the user has disabled emulated FBE.

Force reboot when changing FBE emulation state.

Bug: 26010607, 26027473
Change-Id: Idaf8b63e69f886ddbd848a9fab6d143a5fd10500
This commit is contained in:
Jeff Sharkey
2015-12-07 15:35:42 -07:00
parent 39a275b398
commit ce14cd0141
2 changed files with 61 additions and 28 deletions

View File

@@ -1021,8 +1021,17 @@ public class StorageManager {
/** {@hide} */
public static boolean isFileBasedEncryptionEnabled() {
return "file".equals(SystemProperties.get("ro.crypto.type", "none"))
|| SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
return isNativeFileBasedEncryptionEnabled() || isEmulatedFileBasedEncryptionEnabled();
}
/** {@hide} */
public static boolean isNativeFileBasedEncryptionEnabled() {
return "file".equals(SystemProperties.get("ro.crypto.type", "none"));
}
/** {@hide} */
public static boolean isEmulatedFileBasedEncryptionEnabled() {
return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
}
/** {@hide} */

View File

@@ -57,6 +57,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -175,8 +176,8 @@ class MountService extends IMountService.Stub
}
@Override
public void onStartUser(int userHandle) {
mMountService.onStartUser(userHandle);
public void onUnlockUser(int userHandle) {
mMountService.onUnlockUser(userHandle);
}
@Override
@@ -286,10 +287,12 @@ class MountService extends IMountService.Stub
*/
private final Object mLock = new Object();
/** Set of users that we know are unlocked. */
@GuardedBy("mLock")
private int[] mStartedUsers = EmptyArray.INT;
private int[] mLocalUnlockedUsers = EmptyArray.INT;
/** Set of users that system knows are unlocked. */
@GuardedBy("mLock")
private int[] mUnlockedUsers = EmptyArray.INT;
private int[] mSystemUnlockedUsers = EmptyArray.INT;
/** Map from disk ID to disk */
@GuardedBy("mLock")
@@ -834,12 +837,21 @@ class MountService extends IMountService.Stub
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();
if (mSystemReady && mDaemonConnected
&& !StorageManager.isNativeFileBasedEncryptionEnabled()) {
// When booting a device without native support, make sure that our
// user directories are locked or unlocked based on the current
// emulation status.
final boolean initLocked = StorageManager.isEmulatedFileBasedEncryptionEnabled();
final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
for (UserInfo user : users) {
try {
mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
if (initLocked) {
mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
} else {
mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
user.serialNumber, "!");
}
} catch (NativeDaemonConnectorException e) {
Slog.w(TAG, "Failed to init vold", e);
}
@@ -854,9 +866,9 @@ class MountService extends IMountService.Stub
final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
killMediaProvider(users);
final int[] startedUsers;
final int[] systemUnlockedUsers;
synchronized (mLock) {
startedUsers = mStartedUsers;
systemUnlockedUsers = mSystemUnlockedUsers;
mDisks.clear();
mVolumes.clear();
@@ -871,7 +883,7 @@ class MountService extends IMountService.Stub
for (UserInfo user : users) {
mConnector.execute("volume", "user_added", user.id, user.serialNumber);
}
for (int userId : startedUsers) {
for (int userId : systemUnlockedUsers) {
mConnector.execute("volume", "user_started", userId);
}
} catch (NativeDaemonConnectorException e) {
@@ -880,8 +892,8 @@ class MountService extends IMountService.Stub
}
}
private void onStartUser(int userId) {
Slog.d(TAG, "onStartUser " + userId);
private void onUnlockUser(int userId) {
Slog.d(TAG, "onUnlockUser " + userId);
// We purposefully block here to make sure that user-specific
// staging area is ready so it's ready for zygote-forked apps to
@@ -904,7 +916,7 @@ class MountService extends IMountService.Stub
mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
}
}
mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
}
}
@@ -917,7 +929,7 @@ class MountService extends IMountService.Stub
}
synchronized (mVolumes) {
mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userId);
mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
}
}
@@ -1337,7 +1349,7 @@ class MountService extends IMountService.Stub
// Kick state changed event towards all started users. Any users
// started after this point will trigger additional
// user-specific broadcasts.
for (int userId : mStartedUsers) {
for (int userId : mSystemUnlockedUsers) {
if (vol.isVisibleForRead(userId)) {
final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
@@ -1926,8 +1938,16 @@ class MountService extends IMountService.Stub
waitForReady();
if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
throw new IllegalStateException(
"Emulation not available on device with native FBE");
}
final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
// Perform hard reboot to kick policy into place
mContext.getSystemService(PowerManager.class).reboot(null);
}
if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
@@ -2745,7 +2765,7 @@ class MountService extends IMountService.Stub
}
synchronized (mLock) {
mUnlockedUsers = ArrayUtils.appendInt(mUnlockedUsers, userId);
mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
}
}
@@ -2761,7 +2781,7 @@ class MountService extends IMountService.Stub
}
synchronized (mLock) {
mUnlockedUsers = ArrayUtils.removeInt(mUnlockedUsers, userId);
mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
}
}
@@ -2769,7 +2789,7 @@ class MountService extends IMountService.Stub
public boolean isUserKeyUnlocked(int userId) {
if (StorageManager.isFileBasedEncryptionEnabled()) {
synchronized (mLock) {
return ArrayUtils.contains(mUnlockedUsers, userId);
return ArrayUtils.contains(mLocalUnlockedUsers, userId);
}
} else {
return true;
@@ -2836,21 +2856,25 @@ class MountService extends IMountService.Stub
@Override
public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
final int userId = UserHandle.getUserId(uid);
final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
final ArrayList<StorageVolume> res = new ArrayList<>();
boolean reportUnmounted = false;
boolean foundPrimary = false;
final int userId = UserHandle.getUserId(uid);
final boolean reportUnmounted;
final long identity = Binder.clearCallingIdentity();
try {
reportUnmounted = !mMountServiceInternal.hasExternalStorage(
uid, packageName);
if (!mMountServiceInternal.hasExternalStorage(uid, packageName)) {
reportUnmounted = true;
}
if (!isUserKeyUnlocked(userId)) {
reportUnmounted = true;
}
} finally {
Binder.restoreCallingIdentity(identity);
}
final ArrayList<StorageVolume> res = new ArrayList<>();
synchronized (mLock) {
for (int i = 0; i < mVolumes.size(); i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
@@ -3530,8 +3554,8 @@ class MountService extends IMountService.Stub
pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
pw.println("Force adoptable: " + mForceAdoptable);
pw.println();
pw.println("Started users: " + Arrays.toString(mStartedUsers));
pw.println("Unlocked users: " + Arrays.toString(mUnlockedUsers));
pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
}
synchronized (mObbMounts) {