Keep track of admin actions for DO disclosures

This CL adds bookkeeping to DPMS which will allow us to tell the user
in the Settings UI whether/when the admin requested a bug report or
retrieved logs from the device.

Bug: 32692748
Test: Full DevicePolicyManagerTest unit test coverage; end-to-end tests
        will follow as Settings CTS verifier tests

Change-Id: I89728fce4b7e0ff061b354c73caf3742e95a3a3e
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5ca39b0..0196312 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6749,4 +6749,54 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Called by the system to get the time at which the device owner last retrieved security
+     * logging entries.
+     *
+     * @return the time at which the device owner most recently retrieved security logging entries,
+     *         in milliseconds since epoch; -1 if security logging entries were never retrieved.
+     *
+     * @hide
+     */
+    public long getLastSecurityLogRetrievalTime() {
+        try {
+            return mService.getLastSecurityLogRetrievalTime();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Called by the system to get the time at which the device owner last requested a bug report.
+     *
+     * @return the time at which the device owner most recently requested a bug report, in
+     *         milliseconds since epoch; -1 if a bug report was never requested.
+     *
+     * @hide
+     */
+    public long getLastBugReportRequestTime() {
+        try {
+            return mService.getLastBugReportRequestTime();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Called by the system to get the time at which the device owner last retrieved network logging
+     * events.
+     *
+     * @return the time at which the device owner most recently retrieved network logging events, in
+     *         milliseconds since epoch; -1 if network logging events were never retrieved.
+     *
+     * @hide
+     */
+    public long getLastNetworkLogRetrievalTime() {
+        try {
+            return mService.getLastNetworkLogRetrievalTime();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a2546c0..d14e0d0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -325,4 +325,8 @@
     boolean bindDeviceAdminServiceAsUser(in ComponentName admin,
         IApplicationThread caller, IBinder token, in Intent service,
         IServiceConnection connection, int flags, int targetUserId);
+
+    long getLastSecurityLogRetrievalTime();
+    long getLastBugReportRequestTime();
+    long getLastNetworkLogRetrievalTime();
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 543bba6..0e3d262 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -205,6 +205,12 @@
 
     private static final String TAG_AFFILIATION_ID = "affiliation-id";
 
+    private static final String TAG_LAST_SECURITY_LOG_RETRIEVAL = "last-security-log-retrieval";
+
+    private static final String TAG_LAST_BUG_REPORT_REQUEST = "last-bug-report-request";
+
+    private static final String TAG_LAST_NETWORK_LOG_RETRIEVAL = "last-network-log-retrieval";
+
     private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending";
 
     private static final String ATTR_VALUE = "value";
@@ -466,6 +472,12 @@
 
         Set<String> mAffiliationIds = new ArraySet<>();
 
+        long mLastSecurityLogRetrievalTime = -1;
+
+        long mLastBugReportRequestTime = -1;
+
+        long mLastNetworkLogsRetrievalTime = -1;
+
         // Used for initialization of users created by createAndManageUsers.
         boolean mAdminBroadcastPending = false;
         PersistableBundle mInitBundle = null;
@@ -2359,6 +2371,27 @@
                 out.endTag(null, TAG_AFFILIATION_ID);
             }
 
+            if (policy.mLastSecurityLogRetrievalTime >= 0) {
+                out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL);
+                out.attribute(null, ATTR_VALUE,
+                        Long.toString(policy.mLastSecurityLogRetrievalTime));
+                out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL);
+            }
+
+            if (policy.mLastBugReportRequestTime >= 0) {
+                out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST);
+                out.attribute(null, ATTR_VALUE,
+                        Long.toString(policy.mLastBugReportRequestTime));
+                out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST);
+            }
+
+            if (policy.mLastNetworkLogsRetrievalTime >= 0) {
+                out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL);
+                out.attribute(null, ATTR_VALUE,
+                        Long.toString(policy.mLastNetworkLogsRetrievalTime));
+                out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL);
+            }
+
             if (policy.mAdminBroadcastPending) {
                 out.startTag(null, TAG_ADMIN_BROADCAST_PENDING);
                 out.attribute(null, ATTR_VALUE,
@@ -2515,6 +2548,15 @@
                     policy.doNotAskCredentialsOnBoot = true;
                 } else if (TAG_AFFILIATION_ID.equals(tag)) {
                     policy.mAffiliationIds.add(parser.getAttributeValue(null, "id"));
+                } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) {
+                    policy.mLastSecurityLogRetrievalTime = Long.parseLong(
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) {
+                    policy.mLastBugReportRequestTime = Long.parseLong(
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) {
+                    policy.mLastNetworkLogsRetrievalTime = Long.parseLong(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) {
                     String pending = parser.getAttributeValue(null, ATTR_VALUE);
                     policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending);
@@ -5521,9 +5563,18 @@
             return false;
         }
 
+        final long currentTime = System.currentTimeMillis();
+        synchronized (this) {
+            DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
+            if (currentTime > policyData.mLastBugReportRequestTime) {
+                policyData.mLastBugReportRequestTime = currentTime;
+                saveSettingsLocked(UserHandle.USER_SYSTEM);
+            }
+        }
+
         final long callingIdentity = mInjector.binderClearCallingIdentity();
         try {
-            ActivityManager.getService().requestBugReport(
+            mInjector.getIActivityManager().requestBugReport(
                     ActivityManager.BUGREPORT_OPTION_REMOTE);
 
             mRemoteBugreportServiceIsActive.set(true);
@@ -6530,6 +6581,12 @@
         }
     }
 
+    private void enforceSystemUid() {
+        if (!isCallerWithSystemUid()) {
+            throw new SecurityException("Only the system can call this method.");
+        }
+    }
+
     private void ensureCallerPackage(@Nullable String packageName) {
         if (packageName == null) {
             Preconditions.checkState(isCallerWithSystemUid(),
@@ -9169,6 +9226,15 @@
         }
     }
 
+    private synchronized void recordSecurityLogRetrievalTime() {
+        final long currentTime = System.currentTimeMillis();
+        DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
+        if (currentTime > policyData.mLastSecurityLogRetrievalTime) {
+            policyData.mLastSecurityLogRetrievalTime = currentTime;
+            saveSettingsLocked(UserHandle.USER_SYSTEM);
+        }
+    }
+
     @Override
     public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin) {
         Preconditions.checkNotNull(admin);
@@ -9178,6 +9244,8 @@
             return null;
         }
 
+        recordSecurityLogRetrievalTime();
+
         ArrayList<SecurityEvent> output = new ArrayList<SecurityEvent>();
         try {
             SecurityLog.readPreviousEvents(output);
@@ -9193,6 +9261,8 @@
         Preconditions.checkNotNull(admin);
         ensureDeviceOwnerManagingSingleUser(admin);
 
+        recordSecurityLogRetrievalTime();
+
         List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs();
         return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
     }
@@ -9668,9 +9738,21 @@
         if (mNetworkLogger == null) {
             return null;
         }
-        return isNetworkLoggingEnabledInternalLocked()
-                ? mNetworkLogger.retrieveLogs(batchToken)
-                : null;
+
+        if (!isNetworkLoggingEnabledInternalLocked()) {
+            return null;
+        }
+
+        final long currentTime = System.currentTimeMillis();
+        synchronized (this) {
+            DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
+            if (currentTime > policyData.mLastNetworkLogsRetrievalTime) {
+                policyData.mLastNetworkLogsRetrievalTime = currentTime;
+                saveSettingsLocked(UserHandle.USER_SYSTEM);
+            }
+        }
+
+        return mNetworkLogger.retrieveLogs(batchToken);
     }
 
     /**
@@ -9714,4 +9796,22 @@
         rawIntent.setComponent(info.serviceInfo.getComponentName());
         return rawIntent;
     }
+
+    @Override
+    public long getLastSecurityLogRetrievalTime() {
+        enforceSystemUid();
+        return getUserData(UserHandle.USER_SYSTEM).mLastSecurityLogRetrievalTime;
+     }
+
+    @Override
+    public long getLastBugReportRequestTime() {
+        enforceSystemUid();
+        return getUserData(UserHandle.USER_SYSTEM).mLastBugReportRequestTime;
+     }
+
+    @Override
+    public long getLastNetworkLogRetrievalTime() {
+        enforceSystemUid();
+        return getUserData(UserHandle.USER_SYSTEM).mLastNetworkLogsRetrievalTime;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 80be62b..4927f0c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.database.ContentObserver;
 import android.media.IAudioService;
+import android.net.IIpConnectivityMetrics;
 import android.net.Uri;
 import android.os.Looper;
 import android.os.PowerManagerInternal;
@@ -153,6 +154,11 @@
         }
 
         @Override
+        IIpConnectivityMetrics getIIpConnectivityMetrics() {
+            return context.iipConnectivityMetrics;
+        }
+
+        @Override
         IWindowManager getIWindowManager() {
             return context.iwindowManager;
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 56ff621..98a26ab 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -25,6 +25,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.net.IIpConnectivityMetrics;
 import android.net.wifi.WifiInfo;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -38,6 +41,7 @@
 import android.util.ArraySet;
 import android.util.Pair;
 
+import com.android.internal.R;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
@@ -53,6 +57,7 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNull;
@@ -2248,6 +2253,150 @@
         assertFalse(dpms.hasUserSetupCompleted());
     }
 
+    private long getLastSecurityLogRetrievalTime() {
+        final long ident = mContext.binder.clearCallingIdentity();
+        final long lastSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime();
+        mContext.binder.restoreCallingIdentity(ident);
+        return lastSecurityLogRetrievalTime;
+    }
+
+    public void testGetLastSecurityLogRetrievalTime() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        when(mContext.userManager.getUserCount()).thenReturn(1);
+        when(mContext.resources.getBoolean(R.bool.config_supportPreRebootSecurityLogs))
+                .thenReturn(true);
+
+        // No logs were retrieved so far.
+        assertEquals(-1, getLastSecurityLogRetrievalTime());
+
+        // Enabling logging should not change the timestamp.
+        dpm.setSecurityLoggingEnabled(admin1, true);
+        assertEquals(-1, getLastSecurityLogRetrievalTime());
+
+        // Retrieving the logs should update the timestamp.
+        final long beforeRetrieval = System.currentTimeMillis();
+        dpm.retrieveSecurityLogs(admin1);
+        final long firstSecurityLogRetrievalTime = getLastSecurityLogRetrievalTime();
+        final long afterRetrieval = System.currentTimeMillis();
+        assertTrue(firstSecurityLogRetrievalTime >= beforeRetrieval);
+        assertTrue(firstSecurityLogRetrievalTime <= afterRetrieval);
+
+        // Retrieving the pre-boot logs should update the timestamp.
+        Thread.sleep(2);
+        dpm.retrievePreRebootSecurityLogs(admin1);
+        final long secondSecurityLogRetrievalTime = getLastSecurityLogRetrievalTime();
+        assertTrue(secondSecurityLogRetrievalTime > firstSecurityLogRetrievalTime);
+
+        // Checking the timestamp again should not change it.
+        Thread.sleep(2);
+        assertEquals(secondSecurityLogRetrievalTime, getLastSecurityLogRetrievalTime());
+
+        // Retrieving the logs again should update the timestamp.
+        dpm.retrieveSecurityLogs(admin1);
+        final long thirdSecurityLogRetrievalTime = getLastSecurityLogRetrievalTime();
+        assertTrue(thirdSecurityLogRetrievalTime > secondSecurityLogRetrievalTime);
+
+        // Disabling logging should not change the timestamp.
+        Thread.sleep(2);
+        dpm.setSecurityLoggingEnabled(admin1, false);
+        assertEquals(thirdSecurityLogRetrievalTime, getLastSecurityLogRetrievalTime());
+
+        // Restarting the DPMS should not lose the timestamp.
+        initializeDpms();
+        assertEquals(thirdSecurityLogRetrievalTime, getLastSecurityLogRetrievalTime());
+    }
+
+    private long getLastBugReportRequestTime() {
+        final long ident = mContext.binder.clearCallingIdentity();
+        final long lastBugRequestTime = dpm.getLastBugReportRequestTime();
+        mContext.binder.restoreCallingIdentity(ident);
+        return lastBugRequestTime;
+    }
+
+    public void testGetLastBugReportRequestTime() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        when(mContext.userManager.getUserCount()).thenReturn(1);
+        mContext.packageName = admin1.getPackageName();
+        mContext.applicationInfo = new ApplicationInfo();
+        when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject()))
+                .thenReturn(Color.WHITE);
+        when(mContext.resources.getColor(eq(R.color.notification_material_background_color),
+                anyObject())).thenReturn(Color.WHITE);
+
+        // No bug reports were requested so far.
+        assertEquals(-1, getLastSecurityLogRetrievalTime());
+
+        // Requesting a bug report should update the timestamp.
+        final long beforeRequest = System.currentTimeMillis();
+        dpm.requestBugreport(admin1);
+        final long bugReportRequestTime = getLastBugReportRequestTime();
+        final long afterRequest = System.currentTimeMillis();
+        assertTrue(bugReportRequestTime >= beforeRequest);
+        assertTrue(bugReportRequestTime <= afterRequest);
+
+        // Checking the timestamp again should not change it.
+        Thread.sleep(2);
+        assertEquals(bugReportRequestTime, getLastBugReportRequestTime());
+
+        // Restarting the DPMS should not lose the timestamp.
+        initializeDpms();
+        assertEquals(bugReportRequestTime, getLastBugReportRequestTime());
+    }
+
+    private long getLastNetworkLogRetrievalTime() {
+        final long ident = mContext.binder.clearCallingIdentity();
+        final long lastNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime();
+        mContext.binder.restoreCallingIdentity(ident);
+        return lastNetworkLogRetrievalTime;
+    }
+
+    public void testGetLastNetworkLogRetrievalTime() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        when(mContext.userManager.getUserCount()).thenReturn(1);
+        when(mContext.iipConnectivityMetrics.registerNetdEventCallback(anyObject()))
+                .thenReturn(true);
+
+        // No logs were retrieved so far.
+        assertEquals(-1, getLastNetworkLogRetrievalTime());
+
+        // Attempting to retrieve logs without enabling logging should not change the timestamp.
+        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);
+        assertEquals(-1, getLastNetworkLogRetrievalTime());
+
+        // Enabling logging should not change the timestamp.
+        dpm.setNetworkLoggingEnabled(admin1, true);
+        assertEquals(-1, getLastNetworkLogRetrievalTime());
+
+        // Retrieving the logs should update the timestamp.
+        final long beforeRetrieval = System.currentTimeMillis();
+        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);
+        final long firstNetworkLogRetrievalTime = getLastNetworkLogRetrievalTime();
+        final long afterRetrieval = System.currentTimeMillis();
+        assertTrue(firstNetworkLogRetrievalTime >= beforeRetrieval);
+        assertTrue(firstNetworkLogRetrievalTime <= afterRetrieval);
+
+        // Checking the timestamp again should not change it.
+        Thread.sleep(2);
+        assertEquals(firstNetworkLogRetrievalTime, getLastNetworkLogRetrievalTime());
+
+        // Retrieving the logs again should update the timestamp.
+        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);
+        final long secondNetworkLogRetrievalTime = getLastNetworkLogRetrievalTime();
+        assertTrue(secondNetworkLogRetrievalTime > firstNetworkLogRetrievalTime);
+
+        // Disabling logging should not change the timestamp.
+        Thread.sleep(2);
+        dpm.setNetworkLoggingEnabled(admin1, false);
+        assertEquals(secondNetworkLogRetrievalTime, getLastNetworkLogRetrievalTime());
+
+        // Restarting the DPMS should not lose the timestamp.
+        initializeDpms();
+        assertEquals(secondNetworkLogRetrievalTime, getLastNetworkLogRetrievalTime());
+    }
+
     private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
         when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                 userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 37430ad..d74c6dc 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -26,11 +26,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.media.IAudioService;
+import android.net.IIpConnectivityMetrics;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Handler;
@@ -249,6 +252,7 @@
 
     public final MockBinder binder;
     public final EnvironmentForMock environment;
+    public final Resources resources;
     public final SystemPropertiesForMock systemProperties;
     public final UserManager userManager;
     public final UserManagerInternal userManagerInternal;
@@ -257,6 +261,7 @@
     public final PowerManagerForMock powerManager;
     public final PowerManagerInternal powerManagerInternal;
     public final NotificationManager notificationManager;
+    public final IIpConnectivityMetrics iipConnectivityMetrics;
     public final IWindowManager iwindowManager;
     public final IActivityManager iactivityManager;
     public final IPackageManager ipackageManager;
@@ -278,6 +283,10 @@
 
     public final BuildMock buildMock = new BuildMock();
 
+    public String packageName = null;
+
+    public ApplicationInfo applicationInfo = null;
+
     public DpmMockContext(Context context, File dataDir) {
         realTestContext = context;
 
@@ -286,7 +295,8 @@
 
         binder = new MockBinder();
         environment = mock(EnvironmentForMock.class);
-        systemProperties= mock(SystemPropertiesForMock.class);
+        resources = mock(Resources.class);
+        systemProperties = mock(SystemPropertiesForMock.class);
         userManager = mock(UserManager.class);
         userManagerInternal = mock(UserManagerInternal.class);
         userManagerForMock = mock(UserManagerForMock.class);
@@ -294,6 +304,7 @@
         powerManager = mock(PowerManagerForMock.class);
         powerManagerInternal = mock(PowerManagerInternal.class);
         notificationManager = mock(NotificationManager.class);
+        iipConnectivityMetrics = mock(IIpConnectivityMetrics.class);
         iwindowManager = mock(IWindowManager.class);
         iactivityManager = mock(IActivityManager.class);
         ipackageManager = mock(IPackageManager.class);
@@ -416,6 +427,32 @@
     }
 
     @Override
+    public Resources getResources() {
+        return resources;
+    }
+
+    @Override
+    public Resources.Theme getTheme() {
+        return spiedContext.getTheme();
+    }
+
+    @Override
+    public String getPackageName() {
+        if (packageName != null) {
+            return packageName;
+        }
+        return super.getPackageName();
+    }
+
+    @Override
+    public ApplicationInfo getApplicationInfo() {
+        if (applicationInfo != null) {
+            return applicationInfo;
+        }
+        return super.getApplicationInfo();
+    }
+
+    @Override
     public Object getSystemService(String name) {
         switch (name) {
             case Context.USER_SERVICE:
@@ -615,4 +652,9 @@
     public ContentResolver getContentResolver() {
         return contentResolver;
     }
+
+    @Override
+    public int getUserId() {
+        return UserHandle.getUserId(binder.getCallingUid());
+    }
 }