Added UserInfo.convertedFromPreCreated
This attribute is useful to identify (on bugreports) whether a
user was created "from scratch" or converted from a pre-created user.
Test: adb shell cmd user list --all -v
Test: adb shell dumpsys user
Test: atest UserControllerTest UserManagerServiceUserInfoTest
Bug: 165703573
Change-Id: Iee9df636db5677b4d968d49bb5f5b3fbb9a7f02d
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index aca5b45..08b23b0 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -221,6 +221,14 @@
public boolean preCreated;
/**
+ * When {@code true}, it indicates this user was created by converting a {@link #preCreated}
+ * user.
+ *
+ * <p><b>NOTE: </b>only used for debugging purposes, it's not set when marshalled to a parcel.
+ */
+ public boolean convertedFromPreCreated;
+
+ /**
* Creates a UserInfo whose user type is determined automatically by the flags according to
* {@link #getDefaultUserType}; can only be used for user types handled there.
*/
@@ -413,6 +421,7 @@
lastLoggedInFingerprint = orig.lastLoggedInFingerprint;
partial = orig.partial;
preCreated = orig.preCreated;
+ convertedFromPreCreated = orig.convertedFromPreCreated;
profileGroupId = orig.profileGroupId;
restrictedProfileParentId = orig.restrictedProfileParentId;
guestToRemove = orig.guestToRemove;
@@ -440,6 +449,7 @@
+ ", type=" + userType
+ ", flags=" + flagsToString(flags)
+ (preCreated ? " (pre-created)" : "")
+ + (convertedFromPreCreated ? " (converted)" : "")
+ (partial ? " (partial)" : "")
+ "]";
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6ecaab6..4aaa8a5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -175,6 +175,7 @@
private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
private static final String ATTR_PARTIAL = "partial";
private static final String ATTR_PRE_CREATED = "preCreated";
+ private static final String ATTR_CONVERTED_FROM_PRE_CREATED = "convertedFromPreCreated";
private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
private static final String ATTR_USER_VERSION = "version";
private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
@@ -2912,6 +2913,9 @@
if (userInfo.preCreated) {
serializer.attribute(null, ATTR_PRE_CREATED, "true");
}
+ if (userInfo.convertedFromPreCreated) {
+ serializer.attribute(null, ATTR_CONVERTED_FROM_PRE_CREATED, "true");
+ }
if (userInfo.guestToRemove) {
serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
}
@@ -3069,6 +3073,7 @@
int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
boolean partial = false;
boolean preCreated = false;
+ boolean converted = false;
boolean guestToRemove = false;
boolean persistSeedData = false;
String seedAccountName = null;
@@ -3120,6 +3125,10 @@
if ("true".equals(valueString)) {
preCreated = true;
}
+ valueString = parser.getAttributeValue(null, ATTR_CONVERTED_FROM_PRE_CREATED);
+ if ("true".equals(valueString)) {
+ converted = true;
+ }
valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
if ("true".equals(valueString)) {
guestToRemove = true;
@@ -3177,6 +3186,7 @@
userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
userInfo.partial = partial;
userInfo.preCreated = preCreated;
+ userInfo.convertedFromPreCreated = converted;
userInfo.guestToRemove = guestToRemove;
userInfo.profileGroupId = profileGroupId;
userInfo.profileBadge = profileBadge;
@@ -3610,6 +3620,7 @@
preCreatedUser.name = name;
preCreatedUser.flags = newFlags;
preCreatedUser.preCreated = false;
+ preCreatedUser.convertedFromPreCreated = true;
preCreatedUser.creationTime = getCreationTime();
synchronized (mPackagesLock) {
@@ -4703,6 +4714,7 @@
running ? " (running)" : "",
user.partial ? " (partial)" : "",
user.preCreated ? " (pre-created)" : "",
+ user.convertedFromPreCreated ? " (converted)" : "",
current ? " (current)" : "");
} else {
// NOTE: the standard "list users" command is used by integration tests and
@@ -4788,6 +4800,9 @@
if (userInfo.preCreated) {
pw.print(" <pre-created>");
}
+ if (userInfo.convertedFromPreCreated) {
+ pw.print(" <converted>");
+ }
pw.println();
pw.print(" Type: "); pw.println(userInfo.userType);
pw.print(" Flags: "); pw.print(userInfo.flags); pw.print(" (");
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 66ca839..0ccc026 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -105,7 +105,7 @@
UserData read = mUserManagerService.readUserLP(
data.info.id, new ByteArrayInputStream(bytes));
- assertUserInfoEquals(data.info, read.info);
+ assertUserInfoEquals(data.info, read.info, /* parcelCopy= */ false);
}
@Test
@@ -123,7 +123,16 @@
UserInfo read = UserInfo.CREATOR.createFromParcel(in);
in.recycle();
- assertUserInfoEquals(info, read);
+ assertUserInfoEquals(info, read, /* parcelCopy= */ true);
+ }
+
+ @Test
+ public void testCopyConstructor() throws Exception {
+ UserInfo info = createUser();
+
+ UserInfo copy = new UserInfo(info);
+
+ assertUserInfoEquals(info, copy, /* parcelCopy= */ false);
}
@Test
@@ -227,10 +236,11 @@
user.partial = true;
user.guestToRemove = true;
user.preCreated = true;
+ user.convertedFromPreCreated = true;
return user;
}
- private void assertUserInfoEquals(UserInfo one, UserInfo two) {
+ private void assertUserInfoEquals(UserInfo one, UserInfo two, boolean parcelCopy) {
assertEquals("Id not preserved", one.id, two.id);
assertEquals("Name not preserved", one.name, two.name);
assertEquals("Icon path not preserved", one.iconPath, two.iconPath);
@@ -238,11 +248,17 @@
assertEquals("UserType not preserved", one.userType, two.userType);
assertEquals("profile group not preserved", one.profileGroupId,
two.profileGroupId);
- assertEquals("restricted profile parent not preseved", one.restrictedProfileParentId,
+ assertEquals("restricted profile parent not preserved", one.restrictedProfileParentId,
two.restrictedProfileParentId);
- assertEquals("profile badge not preseved", one.profileBadge, two.profileBadge);
- assertEquals("partial not preseved", one.partial, two.partial);
- assertEquals("guestToRemove not preseved", one.guestToRemove, two.guestToRemove);
- assertEquals("preCreated not preseved", one.preCreated, two.preCreated);
+ assertEquals("profile badge not preserved", one.profileBadge, two.profileBadge);
+ assertEquals("partial not preserved", one.partial, two.partial);
+ assertEquals("guestToRemove not preserved", one.guestToRemove, two.guestToRemove);
+ assertEquals("preCreated not preserved", one.preCreated, two.preCreated);
+ if (parcelCopy) {
+ assertFalse("convertedFromPreCreated should not be set", two.convertedFromPreCreated);
+ } else {
+ assertEquals("convertedFromPreCreated not preserved", one.convertedFromPreCreated,
+ two.convertedFromPreCreated);
+ }
}
}