Loading core/java/android/os/IUserManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -98,4 +98,6 @@ interface IUserManager { boolean isUserNameSet(int userHandle); boolean hasRestrictedProfiles(); boolean trySetQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target); long getUserStartRealtime(); long getUserUnlockRealtime(); } core/java/android/os/UserManager.java +28 −0 Original line number Diff line number Diff line Loading @@ -1391,6 +1391,34 @@ public class UserManager { } } /** * Return the time when the calling user started in elapsed milliseconds since boot, * or 0 if not started. * * @hide */ public long getUserStartRealtime() { try { return mService.getUserStartRealtime(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Return the time when the calling user was unlocked elapsed milliseconds since boot, * or 0 if not unlocked. * * @hide */ public long getUserUnlockRealtime() { try { return mService.getUserUnlockRealtime(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the UserInfo object describing a specific user. * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. Loading services/core/java/com/android/server/pm/UserManagerService.java +86 −18 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.os.SELinux; import android.os.ServiceManager; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; Loading @@ -79,6 +80,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; Loading Loading @@ -241,8 +243,7 @@ public class UserManagerService extends IUserManager.Stub { private static final IBinder mUserRestriconToken = new Binder(); /** * User-related information that is used for persisting to flash. Only UserInfo is * directly exposed to other system apps. * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. */ @VisibleForTesting static class UserData { Loading @@ -260,6 +261,12 @@ public class UserManagerService extends IUserManager.Stub { // Whether to perist the seed account information to be available after a boot boolean persistSeedData; /** Elapsed realtime since boot when the user started. */ long startRealtime; /** Elapsed realtime since boot when the user was unlocked. */ long unlockRealtime; void clearSeedAccountData() { seedAccountName = null; seedAccountType = null; Loading Loading @@ -453,6 +460,37 @@ public class UserManagerService extends IUserManager.Stub { mUms.cleanupPartialUsers(); } } @Override public void onStartUser(int userHandle) { synchronized (mUms.mUsersLock) { final UserData user = mUms.getUserDataLU(userHandle); if (user != null) { user.startRealtime = SystemClock.elapsedRealtime(); } } } @Override public void onUnlockUser(int userHandle) { synchronized (mUms.mUsersLock) { final UserData user = mUms.getUserDataLU(userHandle); if (user != null) { user.unlockRealtime = SystemClock.elapsedRealtime(); } } } @Override public void onStopUser(int userHandle) { synchronized (mUms.mUsersLock) { final UserData user = mUms.getUserDataLU(userHandle); if (user != null) { user.startRealtime = 0; user.unlockRealtime = 0; } } } } // TODO b/28848102 Add support for test dependencies injection Loading Loading @@ -1057,6 +1095,29 @@ public class UserManagerService extends IUserManager.Stub { return mLocalService.isUserRunning(userId); } @Override public long getUserStartRealtime() { final int userId = UserHandle.getUserId(Binder.getCallingUid()); synchronized (mUsersLock) { final UserData user = getUserDataLU(userId); if (user != null) { return user.startRealtime; } return 0; } } @Override public long getUserUnlockRealtime() { synchronized (mUsersLock) { final UserData user = getUserDataLU(UserHandle.getUserId(Binder.getCallingUid())); if (user != null) { return user.unlockRealtime; } return 0; } } private void checkManageOrInteractPermIfCallerInOtherProfileGroup(int userId, String name) { int callingUserId = UserHandle.getCallingUserId(); if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) || Loading Loading @@ -3484,6 +3545,7 @@ public class UserManagerService extends IUserManager.Stub { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; long now = System.currentTimeMillis(); final long nowRealtime = SystemClock.elapsedRealtime(); StringBuilder sb = new StringBuilder(); synchronized (mPackagesLock) { synchronized (mUsersLock) { Loading Loading @@ -3511,25 +3573,20 @@ public class UserManagerService extends IUserManager.Stub { } pw.println(UserState.stateToString(state)); pw.print(" Created: "); if (userInfo.creationTime == 0) { pw.println("<unknown>"); } else { sb.setLength(0); TimeUtils.formatDuration(now - userInfo.creationTime, sb); sb.append(" ago"); pw.println(sb); } dumpTimeAgo(pw, sb, now, userInfo.creationTime); pw.print(" Last logged in: "); if (userInfo.lastLoggedInTime == 0) { pw.println("<unknown>"); } else { sb.setLength(0); TimeUtils.formatDuration(now - userInfo.lastLoggedInTime, sb); sb.append(" ago"); pw.println(sb); } dumpTimeAgo(pw, sb, now, userInfo.lastLoggedInTime); pw.print(" Last logged in fingerprint: "); pw.println(userInfo.lastLoggedInFingerprint); pw.print(" Start time: "); dumpTimeAgo(pw, sb, nowRealtime, userData.startRealtime); pw.print(" Unlock time: "); dumpTimeAgo(pw, sb, nowRealtime, userData.unlockRealtime); pw.print(" Has profile owner: "); pw.println(mIsUserManaged.get(userId)); pw.println(" Restrictions:"); Loading Loading @@ -3593,6 +3650,17 @@ public class UserManagerService extends IUserManager.Stub { } } private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) { if (time == 0) { pw.println("<unknown>"); } else { sb.setLength(0); TimeUtils.formatDuration(nowTime - time, sb); sb.append(" ago"); pw.println(sb); } } final class MainHandler extends Handler { @Override Loading Loading
core/java/android/os/IUserManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -98,4 +98,6 @@ interface IUserManager { boolean isUserNameSet(int userHandle); boolean hasRestrictedProfiles(); boolean trySetQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target); long getUserStartRealtime(); long getUserUnlockRealtime(); }
core/java/android/os/UserManager.java +28 −0 Original line number Diff line number Diff line Loading @@ -1391,6 +1391,34 @@ public class UserManager { } } /** * Return the time when the calling user started in elapsed milliseconds since boot, * or 0 if not started. * * @hide */ public long getUserStartRealtime() { try { return mService.getUserStartRealtime(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Return the time when the calling user was unlocked elapsed milliseconds since boot, * or 0 if not unlocked. * * @hide */ public long getUserUnlockRealtime() { try { return mService.getUserUnlockRealtime(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the UserInfo object describing a specific user. * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. Loading
services/core/java/com/android/server/pm/UserManagerService.java +86 −18 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.os.SELinux; import android.os.ServiceManager; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; Loading @@ -79,6 +80,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; Loading Loading @@ -241,8 +243,7 @@ public class UserManagerService extends IUserManager.Stub { private static final IBinder mUserRestriconToken = new Binder(); /** * User-related information that is used for persisting to flash. Only UserInfo is * directly exposed to other system apps. * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. */ @VisibleForTesting static class UserData { Loading @@ -260,6 +261,12 @@ public class UserManagerService extends IUserManager.Stub { // Whether to perist the seed account information to be available after a boot boolean persistSeedData; /** Elapsed realtime since boot when the user started. */ long startRealtime; /** Elapsed realtime since boot when the user was unlocked. */ long unlockRealtime; void clearSeedAccountData() { seedAccountName = null; seedAccountType = null; Loading Loading @@ -453,6 +460,37 @@ public class UserManagerService extends IUserManager.Stub { mUms.cleanupPartialUsers(); } } @Override public void onStartUser(int userHandle) { synchronized (mUms.mUsersLock) { final UserData user = mUms.getUserDataLU(userHandle); if (user != null) { user.startRealtime = SystemClock.elapsedRealtime(); } } } @Override public void onUnlockUser(int userHandle) { synchronized (mUms.mUsersLock) { final UserData user = mUms.getUserDataLU(userHandle); if (user != null) { user.unlockRealtime = SystemClock.elapsedRealtime(); } } } @Override public void onStopUser(int userHandle) { synchronized (mUms.mUsersLock) { final UserData user = mUms.getUserDataLU(userHandle); if (user != null) { user.startRealtime = 0; user.unlockRealtime = 0; } } } } // TODO b/28848102 Add support for test dependencies injection Loading Loading @@ -1057,6 +1095,29 @@ public class UserManagerService extends IUserManager.Stub { return mLocalService.isUserRunning(userId); } @Override public long getUserStartRealtime() { final int userId = UserHandle.getUserId(Binder.getCallingUid()); synchronized (mUsersLock) { final UserData user = getUserDataLU(userId); if (user != null) { return user.startRealtime; } return 0; } } @Override public long getUserUnlockRealtime() { synchronized (mUsersLock) { final UserData user = getUserDataLU(UserHandle.getUserId(Binder.getCallingUid())); if (user != null) { return user.unlockRealtime; } return 0; } } private void checkManageOrInteractPermIfCallerInOtherProfileGroup(int userId, String name) { int callingUserId = UserHandle.getCallingUserId(); if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) || Loading Loading @@ -3484,6 +3545,7 @@ public class UserManagerService extends IUserManager.Stub { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; long now = System.currentTimeMillis(); final long nowRealtime = SystemClock.elapsedRealtime(); StringBuilder sb = new StringBuilder(); synchronized (mPackagesLock) { synchronized (mUsersLock) { Loading Loading @@ -3511,25 +3573,20 @@ public class UserManagerService extends IUserManager.Stub { } pw.println(UserState.stateToString(state)); pw.print(" Created: "); if (userInfo.creationTime == 0) { pw.println("<unknown>"); } else { sb.setLength(0); TimeUtils.formatDuration(now - userInfo.creationTime, sb); sb.append(" ago"); pw.println(sb); } dumpTimeAgo(pw, sb, now, userInfo.creationTime); pw.print(" Last logged in: "); if (userInfo.lastLoggedInTime == 0) { pw.println("<unknown>"); } else { sb.setLength(0); TimeUtils.formatDuration(now - userInfo.lastLoggedInTime, sb); sb.append(" ago"); pw.println(sb); } dumpTimeAgo(pw, sb, now, userInfo.lastLoggedInTime); pw.print(" Last logged in fingerprint: "); pw.println(userInfo.lastLoggedInFingerprint); pw.print(" Start time: "); dumpTimeAgo(pw, sb, nowRealtime, userData.startRealtime); pw.print(" Unlock time: "); dumpTimeAgo(pw, sb, nowRealtime, userData.unlockRealtime); pw.print(" Has profile owner: "); pw.println(mIsUserManaged.get(userId)); pw.println(" Restrictions:"); Loading Loading @@ -3593,6 +3650,17 @@ public class UserManagerService extends IUserManager.Stub { } } private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) { if (time == 0) { pw.println("<unknown>"); } else { sb.setLength(0); TimeUtils.formatDuration(nowTime - time, sb); sb.append(" ago"); pw.println(sb); } } final class MainHandler extends Handler { @Override Loading