Introduce ephemeral users.
BUG: 24883058
Change-Id: I2e1d6aa184142c2a3dc0415c0cd407573453cf41
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 544fd6a..478164a 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -16,11 +16,11 @@
package com.android.commands.pm;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import android.accounts.IAccountManager;
import android.app.ActivityManager;
@@ -798,6 +798,10 @@
flags |= UserInfo.FLAG_MANAGED_PROFILE;
} else if ("--restricted".equals(opt)) {
flags |= UserInfo.FLAG_RESTRICTED;
+ } else if ("--ephemeral".equals(opt)) {
+ flags |= UserInfo.FLAG_EPHEMERAL;
+ } else if ("--guest".equals(opt)) {
+ flags |= UserInfo.FLAG_GUEST;
} else {
System.err.println("Error: unknown option " + opt);
return showUsage();
@@ -1356,7 +1360,7 @@
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
System.err.println(" pm trim-caches DESIRED_FREE_SPACE [internal|UUID]");
- System.err.println(" pm create-user [--profileOf USER_ID] [--managed] [--restricted] USER_NAME");
+ System.err.println(" pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME");
System.err.println(" pm remove-user USER_ID");
System.err.println(" pm get-max-users");
System.err.println("");
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 6e09595..e3050fe 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -78,6 +78,12 @@
public static final int FLAG_QUIET_MODE = 0x00000080;
+ /**
+ * Indicates that this user is ephemeral. I.e. the user will be removed after leaving
+ * the foreground.
+ */
+ public static final int FLAG_EPHEMERAL = 0x00000100;
+
public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;
public int id;
@@ -134,6 +140,11 @@
public boolean isQuietModeEnabled() {
return (flags & FLAG_QUIET_MODE) == FLAG_QUIET_MODE;
}
+
+ public boolean isEphemeral() {
+ return (flags & FLAG_EPHEMERAL) == FLAG_EPHEMERAL;
+ }
+
/**
* Returns true if the user is a split system user.
* <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c96305e..c8abcef 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -721,6 +721,25 @@
}
/**
+ * Checks if the calling app is running as an ephemeral user.
+ *
+ * @return whether the caller is an ephemeral user.
+ * @hide
+ */
+ public boolean isEphemeralUser() {
+ return isUserEphemeral(UserHandle.myUserId());
+ }
+
+ /**
+ * Returns whether the specified user is ephemeral.
+ * @hide
+ */
+ public boolean isUserEphemeral(int userId) {
+ final UserInfo user = getUserInfo(userId);
+ return user != null && user.isEphemeral();
+ }
+
+ /**
* Return whether the given user is actively running. This means that
* the user is in the "started" state, not "stopped" -- it is currently
* allowed to run code through scheduled alarms, receiving broadcasts,
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index c6510f0..9b3f02d 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -25,8 +25,6 @@
import android.os.Parcelable;
import android.os.RemoteException;
-import java.io.FileDescriptor;
-
/**
* WARNING! Update IMountService.h and IMountService.cpp if you change this
* file. In particular, the ordering of the methods below must match the
@@ -1202,13 +1200,15 @@
}
@Override
- public void createUserKey(int userId, int serialNumber) throws RemoteException {
+ public void createUserKey(int userId, int serialNumber, boolean ephemeral)
+ throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(userId);
_data.writeInt(serialNumber);
+ _data.writeInt(ephemeral ? 1 : 0);
mRemote.transact(Stub.TRANSACTION_createUserKey, _data, _reply, 0);
_reply.readException();
} finally {
@@ -1283,7 +1283,8 @@
}
@Override
- public void prepareUserStorage(String volumeUuid, int userId, int serialNumber)
+ public void prepareUserStorage(
+ String volumeUuid, int userId, int serialNumber, boolean ephemeral)
throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -1292,6 +1293,7 @@
_data.writeString(volumeUuid);
_data.writeInt(userId);
_data.writeInt(serialNumber);
+ _data.writeInt(ephemeral ? 1 : 0);
mRemote.transact(Stub.TRANSACTION_prepareUserStorage, _data, _reply, 0);
_reply.readException();
} finally {
@@ -2012,7 +2014,8 @@
data.enforceInterface(DESCRIPTOR);
int userId = data.readInt();
int serialNumber = data.readInt();
- createUserKey(userId, serialNumber);
+ boolean ephemeral = data.readInt() != 0;
+ createUserKey(userId, serialNumber, ephemeral);
reply.writeNoException();
return true;
}
@@ -2052,7 +2055,8 @@
String volumeUuid = data.readString();
int userId = data.readInt();
int serialNumber = data.readInt();
- prepareUserStorage(volumeUuid, userId, serialNumber);
+ boolean ephemeral = data.readInt() != 0;
+ prepareUserStorage(volumeUuid, userId, serialNumber, ephemeral);
reply.writeNoException();
return true;
}
@@ -2376,15 +2380,16 @@
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
throws RemoteException;
- public void createUserKey(int userId, int serialNumber) throws RemoteException;
+ public void createUserKey(int userId, int serialNumber, boolean ephemeral)
+ throws RemoteException;
public void destroyUserKey(int userId) 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;
- public void prepareUserStorage(String volumeUuid, int userId, int serialNumber)
- throws RemoteException;
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber,
+ boolean ephemeral) throws RemoteException;
public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 7f36a98..beda169 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -966,9 +966,9 @@
}
/** {@hide} */
- public void createUserKey(int userId, int serialNumber) {
+ public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
try {
- mMountService.createUserKey(userId, serialNumber);
+ mMountService.createUserKey(userId, serialNumber, ephemeral);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -1002,9 +1002,10 @@
}
/** {@hide} */
- public void prepareUserStorage(String volumeUuid, int userId, int serialNumber) {
+ public void prepareUserStorage(
+ String volumeUuid, int userId, int serialNumber, boolean ephemeral) {
try {
- mMountService.prepareUserStorage(volumeUuid, userId, serialNumber);
+ mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, ephemeral);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 473eff6..184f890 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2716,12 +2716,13 @@
}
@Override
- public void createUserKey(int userId, int serialNumber) {
+ public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
waitForReady();
try {
- mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber);
+ mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
+ ephemeral ? 1 : 0);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -2797,13 +2798,14 @@
}
@Override
- public void prepareUserStorage(String volumeUuid, int userId, int serialNumber) {
+ public void prepareUserStorage(
+ String volumeUuid, int userId, int serialNumber, boolean ephemeral) {
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
waitForReady();
try {
mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
- userId, serialNumber);
+ userId, serialNumber, ephemeral ? 1 : 0);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d94e5f4..ab8e5a7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16450,7 +16450,7 @@
if (userDir.exists()) continue;
try {
- sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber);
+ sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, user.isEphemeral());
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 e045758..4497e4d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -306,13 +306,13 @@
}
void systemReady() {
- // Prune out any partially created/partially removed users.
+ // Prune out any partially created, partially removed and ephemeral users.
ArrayList<UserInfo> partials = new ArrayList<>();
synchronized (mUsersLock) {
final int userSize = mUsers.size();
for (int i = 0; i < userSize; i++) {
UserInfo ui = mUsers.valueAt(i);
- if ((ui.partial || ui.guestToRemove) && i != 0) {
+ if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
partials.add(ui);
}
}
@@ -1675,6 +1675,10 @@
}
}
}
+
+ if (parent != null && parent.isEphemeral()) {
+ flags |= UserInfo.FLAG_EPHEMERAL;
+ }
userId = getNextAvailableId();
userInfo = new UserInfo(userId, name, null, flags);
userInfo.serialNumber = mNextSerialNumber++;
@@ -1703,12 +1707,13 @@
}
}
final StorageManager storage = mContext.getSystemService(StorageManager.class);
- storage.createUserKey(userId, userInfo.serialNumber);
+ storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final String volumeUuid = vol.getFsUuid();
try {
final File userDir = Environment.getDataUserDirectory(volumeUuid, userId);
- storage.prepareUserStorage(volumeUuid, userId, userInfo.serialNumber);
+ storage.prepareUserStorage(
+ volumeUuid, userId, userInfo.serialNumber, userInfo.isEphemeral());
enforceSerialNumber(userDir, userInfo.serialNumber);
} catch (IOException e) {
Log.wtf(LOG_TAG, "Failed to create user directory on " + volumeUuid, e);