Merge "Added getUserCreationTime to query user/profile creation time"
diff --git a/api/current.txt b/api/current.txt
index 3f1504b..30518ff 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23381,6 +23381,7 @@
     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<android.os.UserHandle> getUserProfiles();
diff --git a/api/system-current.txt b/api/system-current.txt
index 292c314..d3cb1ce 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25264,6 +25264,7 @@
     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<android.os.UserHandle> getUserProfiles();
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 236003b..c2fd3c3 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -38,6 +38,7 @@
     List<UserInfo> 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 3601a1c..afd9950 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1320,4 +1320,19 @@
         }
         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 a8c5527..e79a2061 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 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 @@
         }
     }
 
+    @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 a0b8c94..bfa308e 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 @@
 /** 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<Integer> usersToRemove;
 
     @Override
     public void setUp() throws Exception {
@@ -49,11 +50,19 @@
         }, filter);
 
         removeExistingUsers();
+        usersToRemove = new ArrayList<>();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        for (Integer userId : usersToRemove) {
+            removeUser(userId);
+        }
+        super.tearDown();
     }
 
     private void removeExistingUsers() {
         List<UserInfo> list = mUserManager.getUsers();
-        boolean found = false;
         for (UserInfo user : list) {
             if (user.id != UserHandle.USER_OWNER) {
                 removeUser(user.id);
@@ -66,7 +75,7 @@
     }
 
     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<UserInfo> list = mUserManager.getUsers();
@@ -83,12 +92,11 @@
             }
         }
         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 @@
         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<UserInfo> list = mUserManager.getUsers();
 
@@ -143,40 +175,29 @@
     }
 
     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<UserInfo> created = new ArrayList<UserInfo>();
         // 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 @@
             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;
+    }
+
 }