More file-based encryption work.
Add granular StorageManager APIs for key creation/destruction and
unlocking/locking. Start passing through an opaque token as part
of the unlock command, but leave it empty for now. We now have a
separate "prepare" method that sanity checks that user directories
are correctly setup.
Define a handful of system properties used for marking devices that
should be operating in FBE mode, and if they're emulating FBE. Wire
a command to "sm", but persisting will come later.
Start using new "encryptionAware" flag on apps previously marked with
coreApp flag, which were apps running in the legacy CryptKeeper
model. Small tweaks to handle non-encryptionAware voice interaction
services. Switch PackageManager to consult StorageManager about the
unlocked state of a user.
Bug: 22358539
Change-Id: Ic2865f9b81c10ea39369c441422f7427a3c3c3d6
diff --git a/api/current.txt b/api/current.txt
index c161242..dabc084 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -499,6 +499,7 @@
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
+ field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
field public static final deprecated int endYear = 16843133; // 0x101017d
@@ -559,6 +560,7 @@
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
+ field public static final int forceDeviceEncrypted = 16844037; // 0x1010505
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int foregroundTint = 16843885; // 0x101046d
diff --git a/api/system-current.txt b/api/system-current.txt
index 8729d84..19d9aa2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -591,6 +591,7 @@
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
+ field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
field public static final deprecated int endYear = 16843133; // 0x101017d
@@ -651,6 +652,7 @@
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
+ field public static final int forceDeviceEncrypted = 16844037; // 0x1010505
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int foregroundTint = 16843885; // 0x101046d
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 1ee60b0..b208e43 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -86,6 +86,8 @@
runBenchmark();
} else if ("forget".equals(op)) {
runForget();
+ } else if ("set-emulate-fbe".equals(op)) {
+ runSetEmulateFbe();
} else {
throw new IllegalArgumentException();
}
@@ -137,6 +139,12 @@
StorageManager.DEBUG_FORCE_ADOPTABLE);
}
+ public void runSetEmulateFbe() throws RemoteException {
+ final boolean emulateFbe = Boolean.parseBoolean(nextArg());
+ mSm.setDebugFlags(emulateFbe ? StorageManager.DEBUG_EMULATE_FBE : 0,
+ StorageManager.DEBUG_EMULATE_FBE);
+ }
+
public void runPartition() throws RemoteException {
final String diskId = nextArg();
final String type = nextArg();
@@ -205,6 +213,8 @@
System.err.println("");
System.err.println(" sm forget [UUID|all]");
System.err.println("");
+ System.err.println(" sm set-emulate-fbe [true|false]");
+ System.err.println("");
return 1;
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 52c2f9b..9c880d3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -22,7 +22,9 @@
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Printer;
@@ -469,6 +471,14 @@
public static final int PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED = 1 << 5;
/**
+ * When set, assume that all components under the given app are encryption
+ * aware, unless otherwise specified.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ENCRYPTION_AWARE = 1 << 6;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
@@ -963,7 +973,8 @@
.getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
- if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0) {
+ if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0
+ && SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false)) {
dataDir = deviceEncryptedDataDir;
} else {
dataDir = credentialEncryptedDataDir;
@@ -1030,6 +1041,11 @@
&& (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
+ /** @hide */
+ public boolean isEncryptionAware() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE) != 0;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f176d89..838da37 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2636,6 +2636,10 @@
&& (flags & PARSE_IS_SYSTEM) != 0) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED;
}
+ if (sa.getBoolean(R.styleable.AndroidManifestApplication_encryptionAware, false)
+ && (flags & PARSE_IS_SYSTEM) != 0) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE;
+ }
String str;
str = sa.getNonConfigurationString(
@@ -3236,7 +3240,8 @@
sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
a.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestActivity_encryptionAware, false);
+ R.styleable.AndroidManifestActivity_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
@@ -3253,7 +3258,8 @@
}
a.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestActivity_encryptionAware, false);
+ R.styleable.AndroidManifestActivity_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
}
sa.recycle();
@@ -3655,7 +3661,8 @@
}
p.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestProvider_encryptionAware, false);
+ R.styleable.AndroidManifestProvider_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
sa.recycle();
@@ -3938,7 +3945,8 @@
}
s.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestService_encryptionAware, false);
+ R.styleable.AndroidManifestService_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
sa.recycle();
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 5d45ade..d19c7c9 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1198,14 +1198,14 @@
}
@Override
- public void createNewUserDir(int userHandle, String path) throws RemoteException {
+ public void createUserKey(int userId, int serialNumber) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
- _data.writeInt(userHandle);
- _data.writeString(path);
- mRemote.transact(Stub.TRANSACTION_createNewUserDir, _data, _reply, 0);
+ _data.writeInt(userId);
+ _data.writeInt(serialNumber);
+ mRemote.transact(Stub.TRANSACTION_createUserKey, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
@@ -1214,13 +1214,81 @@
}
@Override
- public void deleteUserKey(int userHandle) throws RemoteException {
+ public void destroyUserKey(int userId) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
- _data.writeInt(userHandle);
- mRemote.transact(Stub.TRANSACTION_deleteUserKey, _data, _reply, 0);
+ _data.writeInt(userId);
+ mRemote.transact(Stub.TRANSACTION_destroyUserKey, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
+ _data.writeInt(serialNumber);
+ _data.writeByteArray(token);
+ mRemote.transact(Stub.TRANSACTION_unlockUserKey, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
+ public void lockUserKey(int userId) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
+ mRemote.transact(Stub.TRANSACTION_lockUserKey, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
+ public boolean isUserKeyUnlocked(int userId) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ boolean _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
+ mRemote.transact(Stub.TRANSACTION_isUserKeyUnlocked, _data, _reply, 0);
+ _reply.readException();
+ _result = 0 != _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ @Override
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber)
+ throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(volumeUuid);
+ _data.writeInt(userId);
+ _data.writeInt(serialNumber);
+ mRemote.transact(Stub.TRANSACTION_prepareUserStorage, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
@@ -1359,13 +1427,17 @@
static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
- static final int TRANSACTION_createNewUserDir = IBinder.FIRST_CALL_TRANSACTION + 62;
+ static final int TRANSACTION_createUserKey = IBinder.FIRST_CALL_TRANSACTION + 61;
+ static final int TRANSACTION_destroyUserKey = IBinder.FIRST_CALL_TRANSACTION + 62;
- static final int TRANSACTION_deleteUserKey = IBinder.FIRST_CALL_TRANSACTION + 63;
+ static final int TRANSACTION_unlockUserKey = IBinder.FIRST_CALL_TRANSACTION + 63;
+ static final int TRANSACTION_lockUserKey = IBinder.FIRST_CALL_TRANSACTION + 64;
+ static final int TRANSACTION_isUserKeyUnlocked = IBinder.FIRST_CALL_TRANSACTION + 65;
- static final int TRANSACTION_isPerUserEncryptionEnabled = IBinder.FIRST_CALL_TRANSACTION + 64;
+ static final int TRANSACTION_prepareUserStorage = IBinder.FIRST_CALL_TRANSACTION + 66;
- static final int TRANSACTION_isConvertibleToFBE = IBinder.FIRST_CALL_TRANSACTION + 65;
+ static final int TRANSACTION_isPerUserEncryptionEnabled = IBinder.FIRST_CALL_TRANSACTION + 67;
+ static final int TRANSACTION_isConvertibleToFBE = IBinder.FIRST_CALL_TRANSACTION + 68;
/**
* Cast an IBinder object into an IMountService interface, generating a
@@ -1929,18 +2001,51 @@
reply.writeNoException();
return true;
}
- case TRANSACTION_createNewUserDir: {
+ case TRANSACTION_createUserKey: {
data.enforceInterface(DESCRIPTOR);
- int userHandle = data.readInt();
- String path = data.readString();
- createNewUserDir(userHandle, path);
+ int userId = data.readInt();
+ int serialNumber = data.readInt();
+ createUserKey(userId, serialNumber);
reply.writeNoException();
return true;
}
- case TRANSACTION_deleteUserKey: {
+ case TRANSACTION_destroyUserKey: {
data.enforceInterface(DESCRIPTOR);
- int userHandle = data.readInt();
- deleteUserKey(userHandle);
+ int userId = data.readInt();
+ destroyUserKey(userId);
+ reply.writeNoException();
+ return true;
+ }
+ case TRANSACTION_unlockUserKey: {
+ data.enforceInterface(DESCRIPTOR);
+ int userId = data.readInt();
+ int serialNumber = data.readInt();
+ byte[] token = data.createByteArray();
+ unlockUserKey(userId, serialNumber, token);
+ reply.writeNoException();
+ return true;
+ }
+ case TRANSACTION_lockUserKey: {
+ data.enforceInterface(DESCRIPTOR);
+ int userId = data.readInt();
+ lockUserKey(userId);
+ reply.writeNoException();
+ return true;
+ }
+ case TRANSACTION_isUserKeyUnlocked: {
+ data.enforceInterface(DESCRIPTOR);
+ int userId = data.readInt();
+ boolean result = isUserKeyUnlocked(userId);
+ reply.writeNoException();
+ reply.writeInt(result ? 1 : 0);
+ return true;
+ }
+ case TRANSACTION_prepareUserStorage: {
+ data.enforceInterface(DESCRIPTOR);
+ String volumeUuid = data.readString();
+ int userId = data.readInt();
+ int serialNumber = data.readInt();
+ prepareUserStorage(volumeUuid, userId, serialNumber);
reply.writeNoException();
return true;
}
@@ -1948,7 +2053,7 @@
data.enforceInterface(DESCRIPTOR);
boolean result = isPerUserEncryptionEnabled();
reply.writeNoException();
- reply.writeInt((result ? 1 : 0));
+ reply.writeInt(result ? 1 : 0);
return true;
}
}
@@ -2263,24 +2368,15 @@
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
throws RemoteException;
- /**
- * Creates the user data directory, possibly encrypted
- * @param userHandle Handle of the user whose directory we are creating
- * @param path Path at which to create the directory.
- */
- public void createNewUserDir(int userHandle, String path)
- throws RemoteException;
+ public void createUserKey(int userId, int serialNumber) throws RemoteException;
+ public void destroyUserKey(int userId) throws RemoteException;
- /**
- * Securely delete the user's encryption key
- * @param userHandle Handle of the user whose key we are deleting
- */
- public void deleteUserKey(int userHandle)
- throws RemoteException;
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) throws RemoteException;
+ public void lockUserKey(int userId) throws RemoteException;
+ public boolean isUserKeyUnlocked(int userId) throws RemoteException;
- /**
- * Returns whether the current encryption type is per user.
- */
- public boolean isPerUserEncryptionEnabled()
- throws RemoteException;
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber)
+ throws RemoteException;
+
+ public boolean isPerUserEncryptionEnabled() throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2ca0b20..27df46d 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -76,7 +76,11 @@
/** {@hide} */
public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
/** {@hide} */
+ public static final String PROP_HAS_FBE = "vold.has_fbe";
+ /** {@hide} */
public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
+ /** {@hide} */
+ public static final String PROP_EMULATE_FBE = "vold.emulate_fbe";
/** {@hide} */
public static final String UUID_PRIVATE_INTERNAL = null;
@@ -85,6 +89,8 @@
/** {@hide} */
public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
+ /** {@hide} */
+ public static final int DEBUG_EMULATE_FBE = 1 << 1;
/** {@hide} */
public static final int FLAG_FOR_WRITE = 1 << 0;
@@ -960,18 +966,54 @@
}
/** {@hide} */
- public void createNewUserDir(int userHandle, File path) {
+ public void createUserKey(int userId, int serialNumber) {
try {
- mMountService.createNewUserDir(userHandle, path.getAbsolutePath());
+ mMountService.createUserKey(userId, serialNumber);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/** {@hide} */
- public void deleteUserKey(int userHandle) {
+ public void destroyUserKey(int userId) {
try {
- mMountService.deleteUserKey(userHandle);
+ mMountService.destroyUserKey(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) {
+ try {
+ mMountService.unlockUserKey(userId, serialNumber, token);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public void lockUserKey(int userId) {
+ try {
+ mMountService.lockUserKey(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber) {
+ try {
+ mMountService.prepareUserStorage(volumeUuid, userId, serialNumber);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public boolean isUserKeyUnlocked(int userId) {
+ try {
+ return mMountService.isUserKeyUnlocked(userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index f190d8c..e8970bc 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -144,6 +144,13 @@
}
/**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(byte[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
* Checks that value is present as at least one of the elements of the array.
* @param array the array to check in
* @param value the value to check for
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 561bcbc..6bdf71b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1683,6 +1683,10 @@
<permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
android:protectionLevel="system|signature" />
+ <!-- @hide -->
+ <permission android:name="android.permission.STORAGE_INTERNAL"
+ android:protectionLevel="signature" />
+
<!-- Allows access to ASEC non-destructive API calls
@hide -->
<permission android:name="android.permission.ASEC_ACCESS"
@@ -2702,7 +2706,9 @@
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_android"
android:supportsRtl="true"
- android:theme="@style/Theme.Material.DayNight.DarkActionBar">
+ android:theme="@style/Theme.Material.DayNight.DarkActionBar"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.DeviceDefault.Resolver"
android:finishOnCloseSystemDialogs="true"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 184f2ab..e376903 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1283,6 +1283,7 @@
<attr name="multiArch" />
<attr name="extractNativeLibs" />
<attr name="forceDeviceEncrypted" format="boolean" />
+ <attr name="encryptionAware" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 037f1c4..43a6acd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2679,6 +2679,8 @@
<public type="attr" name="contextPopupMenuStyle" />
<public type="attr" name="textAppearancePopupMenuHeader" />
<public type="attr" name="windowBackgroundFallback" />
+ <public type="attr" name="forceDeviceEncrypted" />
+ <public type="attr" name="encryptionAware" />
<public type="style" name="Theme.Material.DayNight" />
<public type="style" name="Theme.Material.DayNight.DarkActionBar" />
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index e67c554..ccf1501 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -12,7 +12,9 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<application android:label="@string/service_name"
- android:allowBackup="false">
+ android:allowBackup="false"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<service android:name=".DefaultContainerService"
android:enabled="true"
diff --git a/packages/FakeOemFeatures/AndroidManifest.xml b/packages/FakeOemFeatures/AndroidManifest.xml
index 93b8b47..fe74ad8 100644
--- a/packages/FakeOemFeatures/AndroidManifest.xml
+++ b/packages/FakeOemFeatures/AndroidManifest.xml
@@ -11,7 +11,9 @@
android:allowClearUserData="false"
android:allowBackup="false"
android:hardwareAccelerated="true"
- android:label="Fake OEM Features">
+ android:label="Fake OEM Features"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<service android:name=".FakeCoreService" android:process=":core"
android:label="Fake OEM Core Service" />
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index 6a4d4bf..ed84c0d 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -28,7 +28,9 @@
<application
android:label="@string/app_label"
- android:process="system">
+ android:process="system"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<uses-library android:name="com.android.location.provider" />
@@ -37,7 +39,7 @@
version. -->
<service android:name="com.android.location.fused.FusedLocationService"
android:exported="true"
- android:permission="android.permission.WRITE_SECURE_SETTINGS" >
+ android:permission="android.permission.WRITE_SECURE_SETTINGS">
<intent-filter>
<action android:name="com.android.location.service.FusedLocationProvider" />
</intent-filter>
diff --git a/packages/InputDevices/AndroidManifest.xml b/packages/InputDevices/AndroidManifest.xml
index f0e4abc..07885ea 100644
--- a/packages/InputDevices/AndroidManifest.xml
+++ b/packages/InputDevices/AndroidManifest.xml
@@ -6,7 +6,9 @@
<application
android:allowClearUserData="false"
android:label="@string/app_label"
- android:process="system">
+ android:process="system"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<receiver android:name=".InputDeviceReceiver"
android:label="@string/keyboard_layouts_label">
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index e19246c..54972b4 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -45,7 +45,9 @@
<application android:label="@string/app_name"
android:process="com.android.systemui"
android:persistent="true"
- android:supportsRtl="true">
+ android:supportsRtl="true"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
</application>
</manifest>
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index 71aefad..ba991fb 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -8,11 +8,12 @@
android:process="system"
android:backupAgent="SettingsBackupAgent"
android:killAfterRestore="false"
- android:icon="@mipmap/ic_launcher_settings">
-
- <!-- todo add: android:neverEncrypt="true" -->
+ android:icon="@mipmap/ic_launcher_settings"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
- <provider android:name="SettingsProvider" android:authorities="settings"
+ <provider android:name="SettingsProvider"
+ android:authorities="settings"
android:multiprocess="false"
android:exported="true"
android:singleUser="true"
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 05591cc..8c39ee6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -108,7 +108,9 @@
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
- <application android:label="@string/app_label">
+ <application android:label="@string/app_label"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.android.shell"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index be5c0fe..6fda2c6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -145,7 +145,9 @@
android:icon="@drawable/icon"
android:process="com.android.systemui"
android:supportsRtl="true"
- android:theme="@style/systemui_theme">
+ android:theme="@style/systemui_theme"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<!-- Keep theme in sync with SystemUIApplication.onCreate().
Setting the theme on the application does not affect views inflated by services.
The application theme is set again from onCreate to take effect for those views. -->
diff --git a/packages/services/Proxy/AndroidManifest.xml b/packages/services/Proxy/AndroidManifest.xml
index bbcd6b9..88f8381 100644
--- a/packages/services/Proxy/AndroidManifest.xml
+++ b/packages/services/Proxy/AndroidManifest.xml
@@ -7,7 +7,9 @@
<application
android:label="@string/app_label"
- android:process="com.android.proxyhandler">
+ android:process="com.android.proxyhandler"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<service android:name=".ProxyService"
android:exported="true">
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 6e4f238..37dd884 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -96,6 +96,7 @@
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.NativeDaemonConnector.Command;
@@ -119,6 +120,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -284,6 +286,8 @@
@GuardedBy("mLock")
private int[] mStartedUsers = EmptyArray.INT;
+ @GuardedBy("mLock")
+ private int[] mUnlockedUsers = EmptyArray.INT;
/** Map from disk ID to disk */
@GuardedBy("mLock")
@@ -402,6 +406,17 @@
}
}
+ private static String escapeNull(String arg) {
+ if (TextUtils.isEmpty(arg)) {
+ return "!";
+ } else {
+ if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
+ throw new IllegalArgumentException(arg);
+ }
+ return arg;
+ }
+ }
+
/** List of crypto types.
* These must match CRYPT_TYPE_XXX in cryptfs.h AND their
* corresponding commands in CommandListener.cpp */
@@ -1892,6 +1907,9 @@
if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
}
+ if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
+ // TODO: persist through vold and reboot
+ }
writeSettingsLocked();
mHandler.obtainMessage(H_RESET).sendToTarget();
@@ -2654,65 +2672,99 @@
}
@Override
- public void createNewUserDir(int userHandle, String path) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only SYSTEM_UID can create user directories");
- }
-
+ public void createUserKey(int userId, int serialNumber) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
waitForReady();
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "Creating new user dir");
- }
-
try {
- NativeDaemonEvent event = mCryptConnector.execute(
- "cryptfs", "createnewuserdir", userHandle, path);
- if (!"0".equals(event.getMessage())) {
- String error = "createnewuserdir sent unexpected message: "
- + event.getMessage();
- Slog.e(TAG, error);
- // ext4enc:TODO is this the right exception?
- throw new RuntimeException(error);
- }
+ mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber);
} catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "createnewuserdir threw exception", e);
- throw new RuntimeException("createnewuserdir threw exception", e);
+ throw e.rethrowAsParcelableException();
}
}
- // ext4enc:TODO duplication between this and createNewUserDir is nasty
@Override
- public void deleteUserKey(int userHandle) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only SYSTEM_UID can delete user keys");
- }
-
+ public void destroyUserKey(int userId) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
waitForReady();
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "Deleting user key");
+ try {
+ mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ final String encodedToken;
+ if (ArrayUtils.isEmpty(token)) {
+ encodedToken = "!";
+ } else {
+ encodedToken = HexDump.toHexString(token);
}
try {
- NativeDaemonEvent event = mCryptConnector.execute(
- "cryptfs", "deleteuserkey", userHandle);
- if (!"0".equals(event.getMessage())) {
- String error = "deleteuserkey sent unexpected message: "
- + event.getMessage();
- Slog.e(TAG, error);
- // ext4enc:TODO is this the right exception?
- throw new RuntimeException(error);
- }
+ mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
+ new SensitiveArg(encodedToken));
} catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "deleteuserkey threw exception", e);
- throw new RuntimeException("deleteuserkey threw exception", e);
+ throw e.rethrowAsParcelableException();
+ }
+
+ synchronized (mLock) {
+ mUnlockedUsers = ArrayUtils.appendInt(mUnlockedUsers, userId);
+ }
+ }
+
+ @Override
+ public void lockUserKey(int userId) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ try {
+ mCryptConnector.execute("cryptfs", "lock_user_key", userId);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+
+ synchronized (mLock) {
+ mUnlockedUsers = ArrayUtils.removeInt(mUnlockedUsers, userId);
+ }
+ }
+
+ @Override
+ public boolean isUserKeyUnlocked(int userId) {
+ if (SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false)) {
+ synchronized (mLock) {
+ return ArrayUtils.contains(mUnlockedUsers, userId);
+ }
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ try {
+ mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
+ userId, serialNumber);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
}
}
@Override
public boolean isPerUserEncryptionEnabled() {
- return "file".equals(SystemProperties.get("ro.crypto.type", "none"));
+ // TODO: switch this over to a single property; currently using two to
+ // handle the emulated case
+ return "file".equals(SystemProperties.get("ro.crypto.type", "none"))
+ || SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false);
}
@Override
@@ -3449,6 +3501,9 @@
pw.println();
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));
}
synchronized (mObbMounts) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index cbc13fe..d6fced6 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -18,7 +18,6 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.os.Process.SYSTEM_UID;
@@ -57,8 +56,11 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -134,7 +136,9 @@
mService = service;
mHandler = mService.mHandler;
// User 0 is the first and only user that runs at boot.
- mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true));
+ final UserState uss = new UserState(UserHandle.SYSTEM);
+ mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
+ updateUserUnlockedState(uss);
mUserLru.add(UserHandle.USER_SYSTEM);
updateStartedUserArrayLocked();
}
@@ -409,6 +413,21 @@
return userManager;
}
+ private void updateUserUnlockedState(UserState uss) {
+ final IMountService mountService = IMountService.Stub
+ .asInterface(ServiceManager.getService(Context.STORAGE_SERVICE));
+ if (mountService != null) {
+ try {
+ uss.unlocked = mountService.isUserKeyUnlocked(uss.mHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ } else {
+ // System isn't fully booted yet, so guess based on property
+ uss.unlocked = !SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false);
+ }
+ }
+
boolean startUser(final int userId, final boolean foreground) {
if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
@@ -453,11 +472,14 @@
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
- mStartedUsers.put(userId, new UserState(new UserHandle(userId), false));
+ mStartedUsers.put(userId, new UserState(new UserHandle(userId)));
updateStartedUserArrayLocked();
needStart = true;
}
+ final UserState uss = mStartedUsers.get(userId);
+ updateUserUnlockedState(uss);
+
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
@@ -479,8 +501,6 @@
mUserLru.add(currentUserIdInt);
}
- final UserState uss = mStartedUsers.get(userId);
-
// Make sure user is in the started state. If it is currently
// stopping, we need to knock that off.
if (uss.mState == UserState.STATE_STOPPING) {
@@ -956,8 +976,11 @@
return true;
}
if ((flags & ActivityManager.FLAG_WITH_AMNESIA) != 0) {
- // TODO: add in amnesia lifecycle
- return false;
+ // If user is currently locked, we fall through to default "running"
+ // behavior below
+ if (state.unlocked) {
+ return false;
+ }
}
return state.mState != UserState.STATE_STOPPING
&& state.mState != UserState.STATE_SHUTDOWN;
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index b3d82bc..b5b5c1d 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -40,6 +40,7 @@
public int mState = STATE_BOOTING;
public boolean switching;
public boolean initializing;
+ public boolean unlocked;
/**
* The last time that a provider was reported to usage stats as being brought to important
@@ -47,7 +48,7 @@
*/
public final ArrayMap<String,Long> mProviderLastReportedFg = new ArrayMap<>();
- public UserState(UserHandle handle, boolean initial) {
+ public UserState(UserHandle handle) {
mHandle = handle;
}
@@ -62,6 +63,11 @@
}
if (switching) pw.print(" SWITCHING");
if (initializing) pw.print(" INITIALIZING");
+ if (unlocked) {
+ pw.print(" UNLOCKED");
+ } else {
+ pw.print(" LOCKED");
+ }
pw.println();
}
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 150c849..99a051a 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -185,15 +185,6 @@
return mInstaller.execute(builder.toString());
}
- public int rename(String oldname, String newname) {
- StringBuilder builder = new StringBuilder("rename");
- builder.append(' ');
- builder.append(oldname);
- builder.append(' ');
- builder.append(newname);
- return mInstaller.execute(builder.toString());
- }
-
@Deprecated
public int fixUid(String name, int uid, int gid) {
return fixUid(null, name, uid, gid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ad1cbe6..64628aa 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2981,23 +2981,25 @@
* purposefully done before acquiring {@link #mPackages} lock.
*/
private int augmentFlagsForUser(int flags, int userId) {
- // TODO: bring back once locking fixed
-// final IActivityManager am = ActivityManagerNative.getDefault();
-// if (am == null) {
-// // We must be early in boot, so the best we can do is assume the
-// // user is fully running.
-// return flags;
-// }
-// final long token = Binder.clearCallingIdentity();
-// try {
-// if (am.isUserRunning(userId, ActivityManager.FLAG_WITH_AMNESIA)) {
-// flags |= PackageManager.FLAG_USER_RUNNING_WITH_AMNESIA;
-// }
-// } catch (RemoteException e) {
-// throw e.rethrowAsRuntimeException();
-// } finally {
-// Binder.restoreCallingIdentity(token);
-// }
+ if (SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false)) {
+ final IMountService mount = IMountService.Stub
+ .asInterface(ServiceManager.getService(Context.STORAGE_SERVICE));
+ if (mount == null) {
+ // We must be early in boot, so the best we can do is assume the
+ // user is fully running.
+ return flags;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mount.isUserKeyUnlocked(userId)) {
+ flags |= PackageManager.FLAG_USER_RUNNING_WITH_AMNESIA;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
return flags;
}
@@ -15918,13 +15920,14 @@
}
}
+ final StorageManager sm = mContext.getSystemService(StorageManager.class);
final UserManager um = mContext.getSystemService(UserManager.class);
for (UserInfo user : um.getUsers()) {
final File userDir = Environment.getDataUserDirectory(volumeUuid, user.id);
if (userDir.exists()) continue;
try {
- UserManagerService.prepareUserDirectory(mContext, volumeUuid, user.id);
+ sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber);
UserManagerService.enforceSerialNumber(userDir, user.serialNumber);
} catch (IOException e) {
Log.wtf(TAG, "Failed to create user directory on " + volumeUuid, e);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9a87abe..3a1d2de 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1563,13 +1563,15 @@
userInfo.restrictedProfileParentId = parent.restrictedProfileParentId;
}
}
+
final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ storage.createUserKey(userId, userInfo.serialNumber);
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final String volumeUuid = vol.getFsUuid();
try {
final File userDir = Environment.getDataUserDirectory(volumeUuid,
userId);
- prepareUserDirectory(mContext, volumeUuid, userId);
+ storage.prepareUserStorage(volumeUuid, userId, userInfo.serialNumber);
enforceSerialNumber(userDir, userInfo.serialNumber);
} catch (IOException e) {
Log.wtf(LOG_TAG, "Failed to create user directory on " + volumeUuid, e);
@@ -1797,8 +1799,7 @@
}
private void removeUserStateLILP(final int userHandle) {
- mContext.getSystemService(StorageManager.class)
- .deleteUserKey(userHandle);
+ mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
// Cleanup package manager settings
mPm.cleanUpUserLILPw(this, userHandle);
@@ -2183,16 +2184,6 @@
}
/**
- * Create new {@code /data/user/[id]} directory and sets default
- * permissions.
- */
- public static void prepareUserDirectory(Context context, String volumeUuid, int userId) {
- final StorageManager storage = context.getSystemService(StorageManager.class);
- final File userDir = Environment.getDataUserDirectory(volumeUuid, userId);
- storage.createNewUserDir(userId, userDir);
- }
-
- /**
* Enforce that serial number stored in user directory inode matches the
* given expected value. Gracefully sets the serial number if currently
* undefined.
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index a96c164..f396c2d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -291,21 +291,26 @@
String curService = Settings.Secure.getStringForUser(
mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
ComponentName serviceComponent = null;
+ ServiceInfo serviceInfo = null;
if (curService != null && !curService.isEmpty()) {
try {
serviceComponent = ComponentName.unflattenFromString(curService);
- } catch (RuntimeException e) {
+ serviceInfo = AppGlobals.getPackageManager()
+ .getServiceInfo(serviceComponent, 0, mCurUser);
+ } catch (RuntimeException | RemoteException e) {
Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
serviceComponent = null;
+ serviceInfo = null;
}
}
+
if (force || mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
mSoundTriggerHelper.stopAllRecognitions();
if (mImpl != null) {
mImpl.shutdownLocked();
}
- if (serviceComponent != null) {
+ if (serviceComponent != null && serviceInfo != null) {
mImpl = new VoiceInteractionManagerServiceImpl(mContext,
UiThread.getHandler(), this, mCurUser, serviceComponent);
mImpl.startLocked();