Moved UserMetrics to CarUserService.

Test: adb shell dumpsys car_service --user-metrics
Test: atest CarUserServiceTest VendorServiceControllerTest
Bug: 150222501

Change-Id: I14f099b0e0b24423dffa8c3c6d88611f424ee22a
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index ad45437..e491fee 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -24,7 +24,6 @@
 import android.car.ICar;
 import android.car.cluster.renderer.IInstrumentClusterNavigation;
 import android.car.user.CarUserManager;
-import android.car.user.CarUserManager.UserLifecycleEvent;
 import android.car.userlib.CarUserManagerHelper;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -56,7 +55,6 @@
 import com.android.car.trust.CarTrustedDeviceService;
 import com.android.car.user.CarUserNoticeService;
 import com.android.car.user.CarUserService;
-import com.android.car.user.UserMetrics;
 import com.android.car.vms.VmsBrokerService;
 import com.android.car.watchdog.CarWatchdogService;
 import com.android.internal.annotations.GuardedBy;
@@ -138,8 +136,6 @@
 
     private final String mVehicleInterfaceName;
 
-    private final UserMetrics mUserMetrics = new UserMetrics();
-
     public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
             CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
         this(serviceContext, vehicle, systemInterface, errorNotifier, vehicleInterfaceName,
@@ -360,15 +356,13 @@
         assertCallingFromSystemProcess();
         Log.i(TAG, "onUserLifecycleEvent("
                 + CarUserManager.lifecycleEventTypeToString(eventType) + ", " + toUserId + ")");
-        UserLifecycleEvent event = new UserLifecycleEvent(eventType, toUserId);
-        mCarUserService.onUserLifecycleEvent(event);
-        mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
+        mCarUserService.onUserLifecycleEvent(eventType, timestampMs, fromUserId, toUserId);
     }
 
     @Override
     public void onFirstUserUnlocked(int userId, long timestampMs, long duration,
             int halResponseTime) {
-        mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
+        mCarUserService.onFirstUserUnlocked(userId, timestampMs, duration, halResponseTime);
     }
 
     @Override
@@ -657,7 +651,6 @@
             writer.println("*Dump car service*");
             dumpAllServices(writer);
             dumpAllHals(writer);
-            mUserMetrics.dump(writer);
         } else if ("--list".equals(args[0])) {
             dumpListOfServices(writer);
             return;
@@ -691,9 +684,9 @@
             mHal.dumpListHals(writer);
             return;
         } else if ("--user-metrics".equals(args[0])) {
-            mUserMetrics.dump(writer);
+            mCarUserService.dumpUserMetrics(writer);
         } else if ("--first-user-metrics".equals(args[0])) {
-            mUserMetrics.dumpFirstUserUnlockDuration(writer);
+            mCarUserService.dumpFirstUserUnlockDuration(writer);
         } else if ("--help".equals(args[0])) {
             showDumpHelp(writer);
         } else if (Build.IS_USERDEBUG || Build.IS_ENG) {
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 6d8e69e..578e5c9 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -31,6 +31,7 @@
 import android.car.settings.CarSettings;
 import android.car.user.CarUserManager;
 import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleEventType;
 import android.car.user.CarUserManager.UserLifecycleListener;
 import android.car.userlib.CarUserManagerHelper;
 import android.car.userlib.HalCallback;
@@ -164,6 +165,8 @@
     @GuardedBy("mLockUser")
     private UserInfo mInitialUser;
 
+    private final UserMetrics mUserMetrics = new UserMetrics();
+
     /** Interface for callbaks related to passenger activities. */
     public interface PassengerCallback {
         /** Called when passenger is started at a certain zone. */
@@ -267,6 +270,22 @@
         writer.printf("User switch in process=%d\n", mUserSwitchInProcess);
         writer.printf("Request Id for the user switch in process=%d\n ",
                     mRequestIdForUserSwitchInProcess);
+
+        dumpUserMetrics(writer);
+    }
+
+    /**
+     * Dumps user metrics.
+     */
+    public void dumpUserMetrics(@NonNull PrintWriter writer) {
+        mUserMetrics.dump(writer);
+    }
+
+    /**
+     * Dumps first user unlocking time.
+     */
+    public void dumpFirstUserUnlockDuration(PrintWriter writer) {
+        mUserMetrics.dumpFirstUserUnlockDuration(writer);
     }
 
     private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
@@ -967,9 +986,9 @@
     /**
      * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
      */
-    public void onUserLifecycleEvent(UserLifecycleEvent event) {
-        int userId = event.getUserId();
-        int eventType = event.getEventType();
+    public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
+            @UserIdInt int fromUserId, @UserIdInt int toUserId) {
+        int userId = toUserId;
 
         // Handle special cases first...
         if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
@@ -978,11 +997,24 @@
             onUserUnlocked(userId);
         }
 
-        // ...then notify listeners
+        // ...then notify listeners.
+        UserLifecycleEvent event = new UserLifecycleEvent(eventType, userId);
+
         mHandler.post(() -> {
             handleNotifyServiceUserLifecycleListeners(event);
             handleNotifyAppUserLifecycleListeners(event);
         });
+
+        // Finally, update metrics.
+        mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
+    }
+
+    /**
+     * Sets the first user unlocking metrics.
+     */
+    public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
+            int halResponseTime) {
+        mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
     }
 
     private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
diff --git a/service/src/com/android/car/user/UserMetrics.java b/service/src/com/android/car/user/UserMetrics.java
index e8c62a6..44569de 100644
--- a/service/src/com/android/car/user/UserMetrics.java
+++ b/service/src/com/android/car/user/UserMetrics.java
@@ -53,7 +53,7 @@
  * {{@link #INITIAL_CAPACITY}} occurrences of each when the operation finished (so it can be dumped
  * later).
  */
-public final class UserMetrics {
+final class UserMetrics {
 
     private static final String TAG = UserMetrics.class.getSimpleName();
 
@@ -190,6 +190,10 @@
     @Nullable
     private <T extends BaseUserMetric> T getExistingMetricsLocked(
             @NonNull SparseArray<? extends BaseUserMetric> metrics, @UserIdInt int userId) {
+        if (metrics == null) {
+            Slog.w(TAG, "getExistingMetricsLocked() should not pass null metrics, except on tests");
+            return null;
+        }
         @SuppressWarnings("unchecked")
         T metric = (T) metrics.get(userId);
         if (metric == null) {