From ff7233e2e3df4965b9ecadabfd78bb991fd1e102 Mon Sep 17 00:00:00 2001 From: Fyodor Kupolov Date: Wed, 8 Apr 2015 11:28:52 -0700 Subject: [PATCH] Added getUserCreationTime to query user/profile creation time Added public api to query creation time of the user or of a managed profile associated with the calling user. Bug: 20049349 Change-Id: I7f9263fe434233e6f7d4f165c974cab64ca7107c --- api/current.txt | 1 + api/system-current.txt | 1 + core/java/android/os/IUserManager.aidl | 1 + core/java/android/os/UserManager.java | 15 +++ .../android/server/pm/UserManagerService.java | 45 ++++++-- .../android/server/pm/UserManagerTest.java | 109 ++++++++++++------ 6 files changed, 126 insertions(+), 46 deletions(-) diff --git a/api/current.txt b/api/current.txt index bf55b7c3e4089..9180bd5cd9f00 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23299,6 +23299,7 @@ package android.os { method public android.os.Bundle getApplicationRestrictions(java.lang.String); method public long getSerialNumberForUser(android.os.UserHandle); method public int getUserCount(); + method public long getUserCreationTime(int); method public android.os.UserHandle getUserForSerialNumber(long); method public java.lang.String getUserName(); method public java.util.List getUserProfiles(); diff --git a/api/system-current.txt b/api/system-current.txt index 1152de5fe49a1..3ac4e9fd6ba2e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -25181,6 +25181,7 @@ package android.os { method public android.os.Bundle getApplicationRestrictions(java.lang.String); method public long getSerialNumberForUser(android.os.UserHandle); method public int getUserCount(); + method public long getUserCreationTime(int); method public android.os.UserHandle getUserForSerialNumber(long); method public java.lang.String getUserName(); method public java.util.List getUserProfiles(); diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 236003b85e80b..c2fd3c3582fd1 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -38,6 +38,7 @@ interface IUserManager { List getProfiles(int userHandle, boolean enabledOnly); UserInfo getProfileParent(int userHandle); UserInfo getUserInfo(int userHandle); + long getUserCreationTime(int userHandle); boolean isRestricted(); int getUserSerialNumber(int userHandle); int getUserHandle(int userSerialNumber); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 3601a1c887444..afd9950603807 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1320,4 +1320,19 @@ public class UserManager { } return new Bundle(); } + + /** + * Returns creation time of the user or of a managed profile associated with the calling user. + * @param userHandle user handle of the user or a managed profile associated with the + * calling user. + * @return creation time in milliseconds since Epoch time. + */ + public long getUserCreationTime(int userHandle) { + try { + return mService.getUserCreationTime(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not get user creation time", re); + return 0; + } + } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index a8c55276d2ae0..e79a20618139c 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -327,16 +327,20 @@ public class UserManagerService extends IUserManager.Stub { public UserInfo getProfileParent(int userHandle) { checkManageUsersPermission("get the profile parent"); synchronized (mPackagesLock) { - UserInfo profile = getUserInfoLocked(userHandle); - if (profile == null) { - return null; - } - int parentUserId = profile.profileGroupId; - if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) { - return null; - } else { - return getUserInfoLocked(parentUserId); - } + return getProfileParentLocked(userHandle); + } + } + + private UserInfo getProfileParentLocked(int userHandle) { + UserInfo profile = getUserInfoLocked(userHandle); + if (profile == null) { + return null; + } + int parentUserId = profile.profileGroupId; + if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) { + return null; + } else { + return getUserInfoLocked(parentUserId); } } @@ -1867,6 +1871,27 @@ public class UserManagerService extends IUserManager.Stub { } } + @Override + public long getUserCreationTime(int userHandle) { + int callingUserId = UserHandle.getCallingUserId(); + UserInfo userInfo = null; + synchronized (mPackagesLock) { + if (callingUserId == userHandle) { + userInfo = getUserInfoLocked(userHandle); + } else { + UserInfo parent = getProfileParentLocked(userHandle); + if (parent != null && parent.id == callingUserId) { + userInfo = getUserInfoLocked(userHandle); + } + } + } + if (userInfo == null) { + throw new SecurityException("userHandle can only be the calling user or a managed " + + "profile associated with this user"); + } + return userInfo.creationTime; + } + /** * Caches the list of user ids in an array, adjusting the array size when necessary. */ diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index a0b8c94fa6584..bfa308ea09c35 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -32,8 +32,9 @@ import java.util.List; /** Test {@link UserManager} functionality. */ public class UserManagerTest extends AndroidTestCase { - UserManager mUserManager = null; - Object mUserLock = new Object(); + private UserManager mUserManager = null; + private final Object mUserLock = new Object(); + private List usersToRemove; @Override public void setUp() throws Exception { @@ -49,11 +50,19 @@ public class UserManagerTest extends AndroidTestCase { }, filter); removeExistingUsers(); + usersToRemove = new ArrayList<>(); + } + + @Override + protected void tearDown() throws Exception { + for (Integer userId : usersToRemove) { + removeUser(userId); + } + super.tearDown(); } private void removeExistingUsers() { List list = mUserManager.getUsers(); - boolean found = false; for (UserInfo user : list) { if (user.id != UserHandle.USER_OWNER) { removeUser(user.id); @@ -66,7 +75,7 @@ public class UserManagerTest extends AndroidTestCase { } public void testAddUser() throws Exception { - UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST); + UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST); assertTrue(userInfo != null); List list = mUserManager.getUsers(); @@ -83,12 +92,11 @@ public class UserManagerTest extends AndroidTestCase { } } assertTrue(found); - removeUser(userInfo.id); } public void testAdd2Users() throws Exception { - UserInfo user1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST); - UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_ADMIN); + UserInfo user1 = createUser("Guest 1", UserInfo.FLAG_GUEST); + UserInfo user2 = createUser("User 2", UserInfo.FLAG_ADMIN); assertTrue(user1 != null); assertTrue(user2 != null); @@ -96,41 +104,65 @@ public class UserManagerTest extends AndroidTestCase { assertTrue(findUser(0)); assertTrue(findUser(user1.id)); assertTrue(findUser(user2.id)); - removeUser(user1.id); - removeUser(user2.id); } public void testRemoveUser() throws Exception { - UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST); + UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST); removeUser(userInfo.id); assertFalse(findUser(userInfo.id)); } public void testAddGuest() throws Exception { - UserInfo userInfo1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST); - UserInfo userInfo2 = mUserManager.createUser("Guest 2", UserInfo.FLAG_GUEST); + UserInfo userInfo1 = createUser("Guest 1", UserInfo.FLAG_GUEST); + UserInfo userInfo2 = createUser("Guest 2", UserInfo.FLAG_GUEST); assertNotNull(userInfo1); assertNull(userInfo2); - - // Cleanup - removeUser(userInfo1.id); } // Make sure only one managed profile can be created public void testAddManagedProfile() throws Exception { - UserInfo userInfo1 = mUserManager.createProfileForUser("Managed 1", + UserInfo userInfo1 = createProfileForUser("Managed 1", UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER); - UserInfo userInfo2 = mUserManager.createProfileForUser("Managed 2", + UserInfo userInfo2 = createProfileForUser("Managed 2", UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER); assertNotNull(userInfo1); assertNull(userInfo2); // Verify that current user is not a managed profile assertFalse(mUserManager.isManagedProfile()); - // Cleanup - removeUser(userInfo1.id); } + public void testGetUserCreationTime() throws Exception { + UserInfo profile = createProfileForUser("Managed 1", + UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER); + assertNotNull(profile); + assertTrue("creationTime must be set when the profile is created", + profile.creationTime > 0); + assertEquals(profile.creationTime, mUserManager.getUserCreationTime(profile.id)); + + long ownerCreationTime = mUserManager.getUserInfo(UserHandle.USER_OWNER).creationTime; + assertEquals(ownerCreationTime, mUserManager.getUserCreationTime(UserHandle.USER_OWNER)); + + try { + int noSuchUserId = 100500; + mUserManager.getUserCreationTime(noSuchUserId); + fail("SecurityException should be thrown for nonexistent user"); + } catch (Exception e) { + assertTrue("SecurityException should be thrown for nonexistent user, but was: " + e, + e instanceof SecurityException); + } + + UserInfo user = createUser("User 1", 0); + try { + mUserManager.getUserCreationTime(user.id); + fail("SecurityException should be thrown for other user"); + } catch (Exception e) { + assertTrue("SecurityException should be thrown for other user, but was: " + e, + e instanceof SecurityException); + } + } + + private boolean findUser(int id) { List list = mUserManager.getUsers(); @@ -143,40 +175,29 @@ public class UserManagerTest extends AndroidTestCase { } public void testSerialNumber() { - UserInfo user1 = mUserManager.createUser("User 1", UserInfo.FLAG_RESTRICTED); + UserInfo user1 = createUser("User 1", UserInfo.FLAG_RESTRICTED); int serialNumber1 = user1.serialNumber; assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id)); assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1)); - removeUser(user1.id); - UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_RESTRICTED); + UserInfo user2 = createUser("User 2", UserInfo.FLAG_RESTRICTED); int serialNumber2 = user2.serialNumber; assertFalse(serialNumber1 == serialNumber2); assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id)); assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2)); - removeUser(user2.id); } public void testMaxUsers() { int N = UserManager.getMaxSupportedUsers(); int count = mUserManager.getUsers().size(); - List created = new ArrayList(); // Create as many users as permitted and make sure creation passes while (count < N) { - UserInfo ui = mUserManager.createUser("User " + count, 0); + UserInfo ui = createUser("User " + count, 0); assertNotNull(ui); - created.add(ui); count++; } // Try to create one more user and make sure it fails - UserInfo extra = null; - assertNull(extra = mUserManager.createUser("One more", 0)); - if (extra != null) { - removeUser(extra.id); - } - while (!created.isEmpty()) { - UserInfo user = created.remove(0); - removeUser(user.id); - } + UserInfo extra = createUser("One more", 0); + assertNull(extra); } public void testRestrictions() { @@ -198,11 +219,27 @@ public class UserManagerTest extends AndroidTestCase { mUserManager.removeUser(userId); while (mUserManager.getUserInfo(userId) != null) { try { - mUserLock.wait(1000); + mUserLock.wait(500); } catch (InterruptedException ie) { } } } } + private UserInfo createUser(String name, int flags) { + UserInfo user = mUserManager.createUser(name, flags); + if (user != null) { + usersToRemove.add(user.id); + } + return user; + } + + private UserInfo createProfileForUser(String name, int flags, int userHandle) { + UserInfo profile = mUserManager.createProfileForUser(name, flags, userHandle); + if (profile != null) { + usersToRemove.add(profile.id); + } + return profile; + } + }