Merge "Change isUserUnlocked check to isUserUnlockingOrUnlocked." into qt-qpr1-dev
diff --git a/car_product/init/init.bootstat.rc b/car_product/init/init.bootstat.rc
index 5c5e796..4122ea4 100644
--- a/car_product/init/init.bootstat.rc
+++ b/car_product/init/init.bootstat.rc
@@ -4,4 +4,4 @@
 # This is a common source of Android security bugs.
 #
 on property:boot.car_service_created=1
-    exec - root root -- /system/bin/bootstat -r car_service_created
+    exec - system log -- /system/bin/bootstat -r car_service_created
diff --git a/car_product/sepolicy/private/carservice_app.te b/car_product/sepolicy/private/carservice_app.te
index bc1d74c..6e65a8f 100644
--- a/car_product/sepolicy/private/carservice_app.te
+++ b/car_product/sepolicy/private/carservice_app.te
@@ -12,6 +12,9 @@
 # Allow Car Service to register/access itself with ServiceManager
 add_service(carservice_app, carservice_service)
 
+# Allow Car Service to register its stats service with ServiceManager
+add_service(carservice_app, carstats_service)
+
 allow carservice_app wifi_service:service_manager find;
 
 # Allow Car Service to access certain system services.
diff --git a/car_product/sepolicy/private/service_contexts b/car_product/sepolicy/private/service_contexts
index 7ac544c..38d994c 100644
--- a/car_product/sepolicy/private/service_contexts
+++ b/car_product/sepolicy/private/service_contexts
@@ -1,2 +1,3 @@
 car_service  u:object_r:carservice_service:s0
+car_stats u:object_r:carstats_service:s0
 com.android.car.procfsinspector u:object_r:procfsinspector_service:s0
diff --git a/car_product/sepolicy/private/statsd.te b/car_product/sepolicy/private/statsd.te
new file mode 100644
index 0000000..1a17418
--- /dev/null
+++ b/car_product/sepolicy/private/statsd.te
@@ -0,0 +1,2 @@
+# Allow statsd to pull atoms from car_stats service
+allow statsd carstats_service:service_manager find;
diff --git a/car_product/sepolicy/public/service.te b/car_product/sepolicy/public/service.te
index 87426f4..c6a2e30 100644
--- a/car_product/sepolicy/public/service.te
+++ b/car_product/sepolicy/public/service.te
@@ -1,2 +1,3 @@
 type carservice_service, app_api_service, service_manager_type;
+type carstats_service, service_manager_type;
 type procfsinspector_service, service_manager_type;
diff --git a/car_product/sepolicy/public/te_macros b/car_product/sepolicy/public/te_macros
new file mode 100644
index 0000000..963afdc
--- /dev/null
+++ b/car_product/sepolicy/public/te_macros
@@ -0,0 +1,7 @@
+# Define a macro to allow extra HAL dump
+define(`dump_extra_hal', `
+  hal_client_domain(dumpstate, $1);
+  allow $1_server dumpstate:fifo_file write;
+  allow $1_server dumpstate:fd use;
+  allow dumpstate $1:process signal;
+')
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 81e0620..c756510 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -241,4 +241,8 @@
     <integer name="config_mediaSourceChangedAutoplay">2</integer>
     <!-- Configuration to enable media center to autoplay on boot -->
     <integer name="config_mediaBootAutoplay">2</integer>
+
+    <!-- Disable switching the user while the system is resuming from Suspend to RAM.
+         This default says to prevent changing the user during Resume. -->
+    <bool name="config_disableUserSwitchDuringResume" translatable="false">true</bool>
 </resources>
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index a2f5567..665643a 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -191,6 +191,9 @@
     }
 
     private void maybeInitUser() {
+        if (mCurrentUser == 0) {
+            return;
+        }
         if (mUserManager.isUserUnlocked(mCurrentUser)) {
             initUser();
         } else {
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index c1341da..83c5051 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -54,6 +54,10 @@
  */
 public class CarPowerManagementService extends ICarPower.Stub implements
         CarServiceBase, PowerHalService.PowerEventListener {
+
+    private final Object mLock = new Object();
+    private final Object mSimulationWaitObject = new Object();
+
     private final Context mContext;
     private final PowerHalService mHal;
     private final SystemInterface mSystemInterface;
@@ -62,32 +66,38 @@
     // The listeners that must indicate asynchronous completion by calling finished().
     private final PowerManagerCallbackList mPowerManagerListenersWithCompletion =
                           new PowerManagerCallbackList();
-    private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>();
-    private final Object mSimulationSleepObject = new Object();
 
-    @GuardedBy("this")
+    @GuardedBy("mSimulationWaitObject")
+    private boolean mWakeFromSimulatedSleep;
+    @GuardedBy("mSimulationWaitObject")
+    private boolean mInSimulatedDeepSleepMode;
+
+    @GuardedBy("mLock")
+    private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>();
+    @GuardedBy("mLock")
     private CpmsState mCurrentState;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private Timer mTimer;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private long mProcessingStartTime;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private long mLastSleepEntryTime;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private final LinkedList<CpmsState> mPendingPowerStates = new LinkedList<>();
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private HandlerThread mHandlerThread;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private PowerHandler mHandler;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private boolean mTimerActive;
-    @GuardedBy("mSimulationSleepObject")
-    private boolean mInSimulatedDeepSleepMode = false;
-    @GuardedBy("mSimulationSleepObject")
-    private boolean mWakeFromSimulatedSleep = false;
-    private int mNextWakeupSec = 0;
-    private boolean mShutdownOnFinish = false;
+    @GuardedBy("mLock")
+    private int mNextWakeupSec;
+    @GuardedBy("mLock")
+    private boolean mShutdownOnFinish;
+    @GuardedBy("mLock")
     private boolean mIsBooting = true;
+    @GuardedBy("mLock")
+    private boolean mIsResuming;
 
     private final CarUserManagerHelper mCarUserManagerHelper;
 
@@ -160,7 +170,7 @@
 
     @Override
     public void init() {
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
             mHandlerThread.start();
             mHandler = new PowerHandler(mHandlerThread.getLooper());
@@ -180,11 +190,12 @@
     @Override
     public void release() {
         HandlerThread handlerThread;
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             releaseTimerLocked();
             mCurrentState = null;
             mHandler.cancelAll();
             handlerThread = mHandlerThread;
+            mListenersWeAreWaitingFor.clear();
         }
         handlerThread.quitSafely();
         try {
@@ -194,7 +205,6 @@
         }
         mSystemInterface.stopDisplayStateMonitoring();
         mPowerManagerListeners.kill();
-        mListenersWeAreWaitingFor.clear();
         mSystemInterface.releaseAllWakeLocks();
     }
 
@@ -212,7 +222,7 @@
     @Override
     public void onApPowerStateChange(PowerState state) {
         PowerHandler handler;
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             mPendingPowerStates.addFirst(new CpmsState(state));
             handler = mHandler;
         }
@@ -220,8 +230,11 @@
     }
 
     @VisibleForTesting
-    protected void clearIsBooting() {
-        mIsBooting = false;
+    protected void clearIsBootingOrResuming() {
+        synchronized (mLock) {
+            mIsBooting = false;
+            mIsResuming = false;
+        }
     }
 
     /**
@@ -230,7 +243,7 @@
     private void onApPowerStateChange(int apState, int carPowerStateListenerState) {
         CpmsState newState = new CpmsState(apState, carPowerStateListenerState);
         PowerHandler handler;
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             mPendingPowerStates.addFirst(newState);
             handler = mHandler;
         }
@@ -240,7 +253,7 @@
     private void doHandlePowerStateChange() {
         CpmsState state;
         PowerHandler handler;
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             state = mPendingPowerStates.peekFirst();
             mPendingPowerStates.clear();
             if (state == null) {
@@ -304,10 +317,30 @@
     }
 
     private void handleOn() {
-        // Do not switch user if it is booting as there can be a race with CarServiceHelperService
-        if (mIsBooting) {
-            mIsBooting = false;
-        } else {
+        // Some OEMs have their own user-switching logic, which may not be coordinated with this
+        // code. To avoid contention, we don't switch users when we coming alive. The OEM's code
+        // should do the switch.
+        boolean allowUserSwitch = true;
+        synchronized (mLock) {
+            if (mIsBooting) {
+                // The system is booting, so don't switch users
+                allowUserSwitch = false;
+                mIsBooting = false;
+                mIsResuming = false;
+                Log.i(CarLog.TAG_POWER, "User switch disallowed while booting");
+            } else if (mIsResuming) {
+                // The system is resuming after a suspension. Optionally disable user switching.
+                allowUserSwitch = !mContext.getResources()
+                        .getBoolean(R.bool.config_disableUserSwitchDuringResume);
+                mIsBooting = false;
+                mIsResuming = false;
+                if (!allowUserSwitch) {
+                    Log.i(CarLog.TAG_POWER, "User switch disallowed while resuming");
+                }
+            }
+        }
+
+        if (allowUserSwitch) {
             int targetUserId = mCarUserManagerHelper.getInitialUser();
             if (targetUserId != UserHandle.USER_SYSTEM
                     && targetUserId != mCarUserManagerHelper.getCurrentForegroundUserId()) {
@@ -323,9 +356,11 @@
     private void handleShutdownPrepare(CpmsState newState) {
         mSystemInterface.setDisplayState(false);
         // Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
-        mShutdownOnFinish |= !mHal.isDeepSleepAllowed()
-                || !mSystemInterface.isSystemSupportingDeepSleep()
-                || !newState.mCanSleep;
+        synchronized (mLock) {
+            mShutdownOnFinish |= !mHal.isDeepSleepAllowed()
+                    || !mSystemInterface.isSystemSupportingDeepSleep()
+                    || !newState.mCanSleep;
+        }
         if (newState.mCanPostpone) {
             Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
             sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
@@ -333,7 +368,7 @@
             doHandlePreprocessing();
         } else {
             Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
-            synchronized (CarPowerManagementService.this) {
+            synchronized (mLock) {
                 releaseTimerLocked();
             }
             // Notify hal that we are shutting down and since it is immediate, don't schedule next
@@ -355,21 +390,27 @@
 
     private void handleWaitForFinish(CpmsState state) {
         sendPowerManagerEvent(state.mCarPowerStateListenerState);
+        int wakeupSec;
+        synchronized (mLock) {
+            wakeupSec = mNextWakeupSec;
+        }
         switch (state.mCarPowerStateListenerState) {
             case CarPowerStateListener.SUSPEND_ENTER:
-                mHal.sendSleepEntry(mNextWakeupSec);
+                mHal.sendSleepEntry(wakeupSec);
                 break;
             case CarPowerStateListener.SHUTDOWN_ENTER:
-                mHal.sendShutdownStart(mNextWakeupSec);
+                mHal.sendShutdownStart(wakeupSec);
                 break;
         }
     }
 
     private void handleFinish() {
-        boolean mustShutDown;
         boolean simulatedMode;
-        synchronized (mSimulationSleepObject) {
+        synchronized (mSimulationWaitObject) {
             simulatedMode = mInSimulatedDeepSleepMode;
+        }
+        boolean mustShutDown;
+        synchronized (mLock) {
             mustShutDown = mShutdownOnFinish && !simulatedMode;
         }
         if (mustShutDown) {
@@ -380,15 +421,13 @@
         }
     }
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private void releaseTimerLocked() {
-        synchronized (CarPowerManagementService.this) {
-            if (mTimer != null) {
-                mTimer.cancel();
-            }
-            mTimer = null;
-            mTimerActive = false;
+        if (mTimer != null) {
+            mTimer.cancel();
         }
+        mTimer = null;
+        mTimerActive = false;
     }
 
     private void doHandlePreprocessing() {
@@ -407,7 +446,7 @@
         }
         Log.i(CarLog.TAG_POWER, "processing before shutdown expected for: "
                 + sShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount);
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             mProcessingStartTime = SystemClock.elapsedRealtime();
             releaseTimerLocked();
             mTimer = new Timer();
@@ -433,7 +472,7 @@
         // see the list go empty and we will think that we are done.
         boolean haveSomeCompleters = false;
         PowerManagerCallbackList completingListeners = new PowerManagerCallbackList();
-        synchronized (mListenersWeAreWaitingFor) {
+        synchronized (mLock) {
             mListenersWeAreWaitingFor.clear();
             int idx = mPowerManagerListenersWithCompletion.beginBroadcast();
             while (idx-- > 0) {
@@ -475,28 +514,33 @@
         // enterDeepSleep should force sleep entry even if wake lock is kept.
         mSystemInterface.switchToPartialWakeLock();
         PowerHandler handler;
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             handler = mHandler;
         }
         handler.cancelProcessingComplete();
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             mLastSleepEntryTime = SystemClock.elapsedRealtime();
         }
         int nextListenerState;
         if (simulatedMode) {
-            simulateSleepByLooping();
+            simulateSleepByWaiting();
             nextListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED;
         } else {
             boolean sleepSucceeded = mSystemInterface.enterDeepSleep();
             if (!sleepSucceeded) {
-                // VHAL should transition CPMS to shutdown.
+                // Suspend failed! VHAL should transition CPMS to shutdown.
                 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down.");
                 mSystemInterface.shutdown();
+                return;
             }
             nextListenerState = CarPowerStateListener.SUSPEND_EXIT;
         }
-        // On wake, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
-        mNextWakeupSec = 0;
+        // On resume, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
+        synchronized (mLock) {
+            mIsResuming = true;
+            mNextWakeupSec = 0;
+        }
+        Log.i(CarLog.TAG_POWER, "Resuming after suspending");
         mSystemInterface.refreshDisplayBrightness();
         onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState);
     }
@@ -537,26 +581,24 @@
     }
 
     private void doHandleProcessingComplete() {
-        synchronized (CarPowerManagementService.this) {
+        int listenerState;
+        synchronized (mLock) {
             releaseTimerLocked();
             if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) {
                 // entered sleep after processing start. So this could be duplicate request.
                 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
                 return;
             }
+            listenerState = mShutdownOnFinish
+                    ? CarPowerStateListener.SHUTDOWN_ENTER : CarPowerStateListener.SUSPEND_ENTER;
         }
-
-        if (mShutdownOnFinish) {
-            onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SHUTDOWN_ENTER);
-        } else {
-            onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SUSPEND_ENTER);
-        }
+        onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, listenerState);
     }
 
     @Override
     public void onDisplayBrightnessChange(int brightness) {
         PowerHandler handler;
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             handler = mHandler;
         }
         handler.handleDisplayBrightnessChange(brightness);
@@ -572,7 +614,7 @@
 
     public void handleMainDisplayChanged(boolean on) {
         PowerHandler handler;
-        synchronized (CarPowerManagementService.this) {
+        synchronized (mLock) {
             handler = mHandler;
         }
         handler.handleMainDisplayStateChange(on);
@@ -586,8 +628,13 @@
         mHal.sendDisplayBrightness(brightness);
     }
 
-    public synchronized Handler getHandler() {
-        return mHandler;
+    /**
+     * Get the PowerHandler that we use to change power states
+     */
+    public Handler getHandler() {
+        synchronized (mLock) {
+            return mHandler;
+        }
     }
 
     // Binder interface for general use.
@@ -628,7 +675,9 @@
     @Override
     public void requestShutdownOnNextSuspend() {
         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
-        mShutdownOnFinish = true;
+        synchronized (mLock) {
+            mShutdownOnFinish = true;
+        }
     }
 
     @Override
@@ -639,27 +688,31 @@
     }
 
     @Override
-    public synchronized void scheduleNextWakeupTime(int seconds) {
+    public void scheduleNextWakeupTime(int seconds) {
         if (seconds < 0) {
-            Log.w(CarLog.TAG_POWER, "Next wake up can not be in negative time. Ignoring!");
+            Log.w(CarLog.TAG_POWER, "Next wake up time is negative. Ignoring!");
             return;
         }
-        if (!mHal.isTimedWakeupAllowed()) {
-            Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping");
-            mNextWakeupSec = 0;
-            return;
-        }
-        if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) {
-            mNextWakeupSec = seconds;
-        } else {
-            Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter "
-                    + "scheduled time");
+        boolean timedWakeupAllowed = mHal.isTimedWakeupAllowed();
+        synchronized (mLock) {
+            if (!timedWakeupAllowed) {
+                Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping");
+                mNextWakeupSec = 0;
+                return;
+            }
+            if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) {
+                // The new value is sooner than the old value. Take the new value.
+                mNextWakeupSec = seconds;
+            } else {
+                Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter "
+                        + "scheduled time");
+            }
         }
     }
 
     private void finishedImpl(IBinder binder) {
         boolean allAreComplete = false;
-        synchronized (mListenersWeAreWaitingFor) {
+        synchronized (mLock) {
             boolean oneWasRemoved = mListenersWeAreWaitingFor.remove(binder);
             allAreComplete = oneWasRemoved && mListenersWeAreWaitingFor.isEmpty();
         }
@@ -673,7 +726,7 @@
                 || mCurrentState.mState == CpmsState.SIMULATE_SLEEP) {
             PowerHandler powerHandler;
             // All apps are ready to shutdown/suspend.
-            synchronized (CarPowerManagementService.this) {
+            synchronized (mLock) {
                 if (!mShutdownOnFinish) {
                     if (mLastSleepEntryTime > mProcessingStartTime
                             && mLastSleepEntryTime < SystemClock.elapsedRealtime()) {
@@ -765,7 +818,7 @@
 
         @Override
         public void run() {
-            synchronized (CarPowerManagementService.this) {
+            synchronized (mLock) {
                 if (!mTimerActive) {
                     // Ignore timer expiration since we got cancelled
                     return;
@@ -927,9 +980,9 @@
         }
         handler.handlePowerStateChange();
 
-        synchronized (mSimulationSleepObject) {
+        synchronized (mSimulationWaitObject) {
             mWakeFromSimulatedSleep = true;
-            mSimulationSleepObject.notify();
+            mSimulationWaitObject.notify();
         }
     }
 
@@ -940,12 +993,12 @@
      * that is not directly derived from a VehicleApPowerStateReq.
      */
     public void forceSimulatedSuspend() {
-        synchronized (mSimulationSleepObject) {
+        synchronized (mSimulationWaitObject) {
             mInSimulatedDeepSleepMode = true;
             mWakeFromSimulatedSleep = false;
         }
         PowerHandler handler;
-        synchronized (this) {
+        synchronized (mLock) {
             mPendingPowerStates.addFirst(new CpmsState(CpmsState.SIMULATE_SLEEP,
                                                        CarPowerStateListener.SHUTDOWN_PREPARE));
             handler = mHandler;
@@ -956,19 +1009,20 @@
     // In a real Deep Sleep, the hardware removes power from the CPU (but retains power
     // on the RAM). This puts the processor to sleep. Upon some external signal, power
     // is re-applied to the CPU, and processing resumes right where it left off.
-    // We simulate this behavior by simply going into a loop.
-    // We exit the loop when forceResume() is called.
-    private void simulateSleepByLooping() {
-        Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by looping");
-        synchronized (mSimulationSleepObject) {
+    // We simulate this behavior by calling wait().
+    // We continue from wait() when forceSimulatedResume() is called.
+    private void simulateSleepByWaiting() {
+        Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by waiting");
+        synchronized (mSimulationWaitObject) {
             while (!mWakeFromSimulatedSleep) {
                 try {
-                    mSimulationSleepObject.wait();
+                    mSimulationWaitObject.wait();
                 } catch (InterruptedException ignored) {
+                    Thread.currentThread().interrupt(); // Restore interrupted status
                 }
             }
             mInSimulatedDeepSleepMode = false;
         }
-        Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation loop");
+        Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation");
     }
 }
diff --git a/service/src/com/android/car/CarService.java b/service/src/com/android/car/CarService.java
index fdc4995..044c791 100644
--- a/service/src/com/android/car/CarService.java
+++ b/service/src/com/android/car/CarService.java
@@ -99,6 +99,7 @@
         linkToDeath(mVehicle, mVehicleDeathRecipient);
 
         ServiceManager.addService("car_service", mICarImpl);
+        ServiceManager.addService("car_stats", mICarImpl.getStatsService());
         SystemProperties.set("boot.car_service_created", "1");
         super.onCreate();
     }
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index d98b780..0c50da9 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -386,6 +386,10 @@
         }
     }
 
+    CarStatsService getStatsService() {
+        return mCarStatsService;
+    }
+
     public static void assertVehicleHalMockPermission(Context context) {
         assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
     }
@@ -490,6 +494,7 @@
             }
         } else if ("--metrics".equals(args[0])) {
             // Strip the --metrics flag when passing dumpsys arguments to CarStatsService
+            // allowing for nested flag selection
             mCarStatsService.dump(fd, writer, Arrays.copyOfRange(args, 1, args.length));
         } else if ("--vms-hal".equals(args[0])) {
             mHal.getVmsHal().dumpMetrics(fd);
diff --git a/service/src/com/android/car/VmsPublisherService.java b/service/src/com/android/car/VmsPublisherService.java
index da0b8b7..def10dd 100644
--- a/service/src/com/android/car/VmsPublisherService.java
+++ b/service/src/com/android/car/VmsPublisherService.java
@@ -181,7 +181,7 @@
             }
 
             int payloadLength = payload != null ? payload.length : 0;
-            mStatsService.getVmsClientLog(mGetCallingUid.getAsInt())
+            mStatsService.getVmsClientLogger(mGetCallingUid.getAsInt())
                     .logPacketSent(layer, payloadLength);
 
             // Send the message to subscribers
@@ -192,7 +192,7 @@
 
             if (listeners.size() == 0) {
                 // A negative UID signals that the packet had zero subscribers
-                mStatsService.getVmsClientLog(-1)
+                mStatsService.getVmsClientLogger(-1)
                         .logPacketDropped(layer, payloadLength);
             }
 
@@ -200,10 +200,10 @@
                 int subscriberUid = mClientManager.getSubscriberUid(listener);
                 try {
                     listener.onVmsMessageReceived(layer, payload);
-                    mStatsService.getVmsClientLog(subscriberUid)
+                    mStatsService.getVmsClientLogger(subscriberUid)
                             .logPacketReceived(layer, payloadLength);
                 } catch (RemoteException ex) {
-                    mStatsService.getVmsClientLog(subscriberUid)
+                    mStatsService.getVmsClientLogger(subscriberUid)
                             .logPacketDropped(layer, payloadLength);
                     String subscriberName = mClientManager.getPackageName(listener);
                     Log.e(TAG, String.format("Unable to publish to listener: %s", subscriberName));
diff --git a/service/src/com/android/car/audio/CarAudioFocus.java b/service/src/com/android/car/audio/CarAudioFocus.java
index 165caad..286a045 100644
--- a/service/src/com/android/car/audio/CarAudioFocus.java
+++ b/service/src/com/android/car/audio/CarAudioFocus.java
@@ -113,6 +113,10 @@
                             mAfi.getPackageName())
                     == PackageManager.PERMISSION_GRANTED);
         }
+
+        String getUsageName() {
+            return mAfi.getAttributes().usageToString();
+        }
     }
 
 
@@ -171,8 +175,9 @@
     // The default audio framework's behavior is to remove the previous entry in the stack (no-op
     // if the requester is already holding focus).
     int evaluateFocusRequest(AudioFocusInfo afi) {
-        Log.i(TAG, "Evaluating " + focusEventToString(afi.getGainRequest()) + " request for client "
-                + afi.getClientId());
+        Log.i(TAG, "Evaluating " + focusEventToString(afi.getGainRequest())
+                + " request for client " + afi.getClientId()
+                + " with usage " + afi.getAttributes().usageToString());
 
         // Is this a request for premanant focus?
         // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -- Means Notifications should be denied
@@ -588,14 +593,17 @@
     public synchronized void dump(String indent, PrintWriter writer) {
         writer.printf("%s*CarAudioFocus*\n", indent);
 
-        writer.printf("%s\tCurrent Focus Holders:\n", indent);
+        String innerIndent = indent + "\t";
+        writer.printf("%sCurrent Focus Holders:\n", innerIndent);
         for (String clientId : mFocusHolders.keySet()) {
-            writer.printf("%s\t\t%s\n", indent, clientId);
+            writer.printf("%s\t%s - %s\n", innerIndent, clientId,
+                    mFocusHolders.get(clientId).getUsageName());
         }
 
-        writer.printf("%s\tTransient Focus Losers:\n", indent);
+        writer.printf("%sTransient Focus Losers:\n", innerIndent);
         for (String clientId : mFocusLosers.keySet()) {
-            writer.printf("%s\t\t%s\n", indent, clientId);
+            writer.printf("%s\t%s - %s\n", innerIndent, clientId,
+                    mFocusLosers.get(clientId).getUsageName());
         }
     }
 
diff --git a/service/src/com/android/car/stats/CarStatsService.java b/service/src/com/android/car/stats/CarStatsService.java
index db23355..d74fb8c 100644
--- a/service/src/com/android/car/stats/CarStatsService.java
+++ b/service/src/com/android/car/stats/CarStatsService.java
@@ -16,33 +16,42 @@
 
 package com.android.car.stats;
 
+import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.StatsLogEventWrapper;
+import android.os.SystemClock;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.StatsLog;
 
-import com.android.car.stats.VmsClientLog.ConnectionState;
+import com.android.car.stats.VmsClientLogger.ConnectionState;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.car.ICarStatsService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.function.Consumer;
 import java.util.function.Function;
 
 /**
- * Implements collection and dumpsys reporting of statistics in CSV format.
+ * Implementation of {@link ICarStatsService}, for reporting pulled atoms via statsd.
+ *
+ * Also implements collection and dumpsys reporting of atoms in CSV format.
  */
-public class CarStatsService {
+public class CarStatsService extends ICarStatsService.Stub {
     private static final boolean DEBUG = false;
     private static final String TAG = "CarStatsService";
     private static final String VMS_CONNECTION_STATS_DUMPSYS_HEADER =
             "uid,packageName,attempts,connected,disconnected,terminated,errors";
 
-    private static final Function<VmsClientLog, String> VMS_CONNECTION_STATS_DUMPSYS_FORMAT =
+    private static final Function<VmsClientLogger, String> VMS_CONNECTION_STATS_DUMPSYS_FORMAT =
             entry -> String.format(Locale.US,
                     "%d,%s,%d,%d,%d,%d,%d",
                     entry.getUid(), entry.getPackageName(),
@@ -71,19 +80,21 @@
                     .thenComparingInt(VmsClientStats::getLayerChannel)
                     .thenComparingInt(VmsClientStats::getLayerVersion);
 
+    private final Context mContext;
     private final PackageManager mPackageManager;
 
     @GuardedBy("mVmsClientStats")
-    private final Map<Integer, VmsClientLog> mVmsClientStats = new ArrayMap<>();
+    private final Map<Integer, VmsClientLogger> mVmsClientStats = new ArrayMap<>();
 
     public CarStatsService(Context context) {
+        mContext = context;
         mPackageManager = context.getPackageManager();
     }
 
     /**
      * Gets a logger for the VMS client with a given UID.
      */
-    public VmsClientLog getVmsClientLog(int clientUid) {
+    public VmsClientLogger getVmsClientLogger(int clientUid) {
         synchronized (mVmsClientStats) {
             return mVmsClientStats.computeIfAbsent(
                     clientUid,
@@ -92,14 +103,12 @@
                         if (DEBUG) {
                             Log.d(TAG, "Created VmsClientLog: " + packageName);
                         }
-                        return new VmsClientLog(uid, packageName);
+                        return new VmsClientLogger(uid, packageName);
                     });
         }
     }
 
-    /**
-     * Dumps metrics in CSV format.
-     */
+    @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         List<String> flags = Arrays.asList(args);
         if (args.length == 0 || flags.contains("--vms-client")) {
@@ -107,6 +116,21 @@
         }
     }
 
+    @Override
+    public StatsLogEventWrapper[] pullData(int tagId) {
+        mContext.enforceCallingPermission(Manifest.permission.DUMP, null);
+        if (tagId != StatsLog.VMS_CLIENT_STATS) {
+            Log.w(TAG, "Unexpected tagId: " + tagId);
+            return null;
+        }
+
+        List<StatsLogEventWrapper> ret = new ArrayList<>();
+        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        long wallClockNanos = SystemClock.currentTimeMicro() * 1000L;
+        pullVmsClientStats(tagId, elapsedNanos, wallClockNanos, ret);
+        return ret.toArray(new StatsLogEventWrapper[0]);
+    }
+
     private void dumpVmsStats(PrintWriter writer) {
         synchronized (mVmsClientStats) {
             writer.println(VMS_CONNECTION_STATS_DUMPSYS_HEADER);
@@ -114,17 +138,44 @@
                     // Unknown UID will not have connection stats
                     .filter(entry -> entry.getUid() > 0)
                     // Sort stats by UID
-                    .sorted(Comparator.comparingInt(VmsClientLog::getUid))
+                    .sorted(Comparator.comparingInt(VmsClientLogger::getUid))
                     .forEachOrdered(entry -> writer.println(
                             VMS_CONNECTION_STATS_DUMPSYS_FORMAT.apply(entry)));
             writer.println();
 
             writer.println(VMS_CLIENT_STATS_DUMPSYS_HEADER);
+            dumpVmsClientStats(entry -> writer.println(
+                    VMS_CLIENT_STATS_DUMPSYS_FORMAT.apply(entry)));
+        }
+    }
+
+    private void pullVmsClientStats(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        dumpVmsClientStats((entry) -> {
+            StatsLogEventWrapper e =
+                    new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+            e.writeInt(entry.getUid());
+
+            e.writeInt(entry.getLayerType());
+            e.writeInt(entry.getLayerChannel());
+            e.writeInt(entry.getLayerVersion());
+
+            e.writeLong(entry.getTxBytes());
+            e.writeLong(entry.getTxPackets());
+            e.writeLong(entry.getRxBytes());
+            e.writeLong(entry.getRxPackets());
+            e.writeLong(entry.getDroppedBytes());
+            e.writeLong(entry.getDroppedPackets());
+            pulledData.add(e);
+        });
+    }
+
+    private void dumpVmsClientStats(Consumer<VmsClientStats> dumpFn) {
+        synchronized (mVmsClientStats) {
             mVmsClientStats.values().stream()
                     .flatMap(log -> log.getLayerEntries().stream())
                     .sorted(VMS_CLIENT_STATS_ORDER)
-                    .forEachOrdered(entry -> writer.println(
-                            VMS_CLIENT_STATS_DUMPSYS_FORMAT.apply(entry)));
+                    .forEachOrdered(dumpFn);
         }
     }
 }
diff --git a/service/src/com/android/car/stats/VmsClientLog.java b/service/src/com/android/car/stats/VmsClientLogger.java
similarity index 81%
rename from service/src/com/android/car/stats/VmsClientLog.java
rename to service/src/com/android/car/stats/VmsClientLogger.java
index 506a5fc..948db05 100644
--- a/service/src/com/android/car/stats/VmsClientLog.java
+++ b/service/src/com/android/car/stats/VmsClientLogger.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.car.vms.VmsLayer;
 import android.util.ArrayMap;
+import android.util.StatsLog;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -30,21 +31,26 @@
 /**
  * Logger for per-client VMS statistics.
  */
-public class VmsClientLog {
+public class VmsClientLogger {
     /**
      * Constants used for identifying client connection states.
      */
     public static class ConnectionState {
         // Attempting to connect to the client
-        public static final int CONNECTING = 0;
+        public static final int CONNECTING =
+                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTING;
         // Client connection established
-        public static final int CONNECTED = 1;
+        public static final int CONNECTED =
+                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTED;
         // Client connection closed unexpectedly
-        public static final int DISCONNECTED = 2;
+        public static final int DISCONNECTED =
+                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__DISCONNECTED;
         // Client connection closed by VMS
-        public static final int TERMINATED = 3;
+        public static final int TERMINATED =
+                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__TERMINATED;
         // Error establishing the client connection
-        public static final int CONNECTION_ERROR = 4;
+        public static final int CONNECTION_ERROR =
+                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTION_ERROR;
     }
 
     private final Object mLock = new Object();
@@ -58,7 +64,7 @@
     @GuardedBy("mLock")
     private final Map<VmsLayer, VmsClientStats> mLayerStats = new ArrayMap<>();
 
-    VmsClientLog(int clientUid, @Nullable String clientPackage) {
+    VmsClientLogger(int clientUid, @Nullable String clientPackage) {
         mUid = clientUid;
         mPackageName = clientPackage != null ? clientPackage : "";
     }
@@ -77,6 +83,9 @@
      * @param connectionState New connection state
      */
     public void logConnectionState(int connectionState) {
+        StatsLog.write(StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED,
+                mUid, mPackageName, connectionState);
+
         AtomicLong counter;
         synchronized (mLock) {
             counter = mConnectionStateCounters.computeIfAbsent(connectionState,
diff --git a/service/src/com/android/car/stats/VmsClientStats.java b/service/src/com/android/car/stats/VmsClientStats.java
index f4ce7b8..9fbe1dd 100644
--- a/service/src/com/android/car/stats/VmsClientStats.java
+++ b/service/src/com/android/car/stats/VmsClientStats.java
@@ -56,15 +56,15 @@
      * @param layer Vehicle Maps Service layer.
      */
     VmsClientStats(int uid, VmsLayer layer) {
-        this.mUid = uid;
+        mUid = uid;
 
-        this.mLayerType = layer.getType();
-        this.mLayerChannel = layer.getSubtype();
-        this.mLayerVersion = layer.getVersion();
+        mLayerType = layer.getType();
+        mLayerChannel = layer.getSubtype();
+        mLayerVersion = layer.getVersion();
     }
 
     /**
-     * Copy constructor for entries exported from {@link VmsClientLog} to {@link CarStatsService}.
+     * Copy constructor for entries exported from {@link VmsClientLogger}.
      */
     VmsClientStats(VmsClientStats other) {
         synchronized (other.mLock) {
diff --git a/service/src/com/android/car/vms/VmsClientManager.java b/service/src/com/android/car/vms/VmsClientManager.java
index 4f7400f..f2c4813 100644
--- a/service/src/com/android/car/vms/VmsClientManager.java
+++ b/service/src/com/android/car/vms/VmsClientManager.java
@@ -41,8 +41,8 @@
 import com.android.car.VmsPublisherService;
 import com.android.car.hal.VmsHalService;
 import com.android.car.stats.CarStatsService;
-import com.android.car.stats.VmsClientLog;
-import com.android.car.stats.VmsClientLog.ConnectionState;
+import com.android.car.stats.VmsClientLogger;
+import com.android.car.stats.VmsClientLogger.ConnectionState;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -311,7 +311,7 @@
                     new SubscriberConnection(subscriberClient, Process.myUid(), HAL_CLIENT_NAME,
                             UserHandle.USER_SYSTEM));
         }
-        mStatsService.getVmsClientLog(Process.myUid())
+        mStatsService.getVmsClientLogger(Process.myUid())
                 .logConnectionState(ConnectionState.CONNECTED);
     }
 
@@ -322,7 +322,7 @@
         synchronized (mLock) {
             if (mHalClient != null) {
                 mPublisherService.onClientDisconnected(HAL_CLIENT_NAME);
-                mStatsService.getVmsClientLog(Process.myUid())
+                mStatsService.getVmsClientLogger(Process.myUid())
                         .logConnectionState(ConnectionState.DISCONNECTED);
             }
             mHalClient = null;
@@ -405,7 +405,7 @@
             return;
         }
 
-        VmsClientLog statsLog = mStatsService.getVmsClientLog(
+        VmsClientLogger statsLog = mStatsService.getVmsClientLogger(
                 UserHandle.getUid(userHandle.getIdentifier(), serviceInfo.applicationInfo.uid));
 
         if (!Car.PERMISSION_BIND_VMS_CLIENT.equals(serviceInfo.permission)) {
@@ -433,13 +433,13 @@
         private final ComponentName mName;
         private final UserHandle mUser;
         private final String mFullName;
-        private final VmsClientLog mStatsLog;
+        private final VmsClientLogger mStatsLog;
         private boolean mIsBound = false;
         private boolean mIsTerminated = false;
         private boolean mRebindScheduled = false;
         private IVmsPublisherClient mClientService;
 
-        PublisherConnection(ComponentName name, UserHandle user, VmsClientLog statsLog) {
+        PublisherConnection(ComponentName name, UserHandle user, VmsClientLogger statsLog) {
             mName = name;
             mUser = user;
             mFullName = mName.flattenToString() + " U=" + mUser.getIdentifier();
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
index fa82f90..945a9d6 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
@@ -197,7 +197,7 @@
         // second processing after wakeup
         assertFalse(mDisplayInterface.getDisplayState());
         // do not skip user switching part.
-        mService.clearIsBooting();
+        mService.clearIsBootingOrResuming();
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
         // user switching should have been requested.
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java b/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
index 2704654..2bd09df 100644
--- a/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
@@ -44,7 +44,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.car.stats.CarStatsService;
-import com.android.car.stats.VmsClientLog;
+import com.android.car.stats.VmsClientLogger;
 import com.android.car.vms.VmsBrokerService;
 import com.android.car.vms.VmsClientManager;
 
@@ -92,13 +92,13 @@
     private VmsClientManager mClientManager;
 
     @Mock
-    private VmsClientLog mPublisherLog;
+    private VmsClientLogger mPublisherLog;
     @Mock
-    private VmsClientLog mSubscriberLog;
+    private VmsClientLogger mSubscriberLog;
     @Mock
-    private VmsClientLog mSubscriberLog2;
+    private VmsClientLogger mSubscriberLog2;
     @Mock
-    private VmsClientLog mNoSubscribersLog;
+    private VmsClientLogger mNoSubscribersLog;
 
     @Mock
     private IVmsSubscriberClient mSubscriberClient;
@@ -118,10 +118,10 @@
         when(mClientManager.getSubscriberUid(mSubscriberClient)).thenReturn(SUBSCRIBER_UID);
         when(mClientManager.getSubscriberUid(mSubscriberClient2)).thenReturn(SUBSCRIBER_UID2);
 
-        when(mStatsService.getVmsClientLog(PUBLISHER_UID)).thenReturn(mPublisherLog);
-        when(mStatsService.getVmsClientLog(SUBSCRIBER_UID)).thenReturn(mSubscriberLog);
-        when(mStatsService.getVmsClientLog(SUBSCRIBER_UID2)).thenReturn(mSubscriberLog2);
-        when(mStatsService.getVmsClientLog(NO_SUBSCRIBERS_UID)).thenReturn(mNoSubscribersLog);
+        when(mStatsService.getVmsClientLogger(PUBLISHER_UID)).thenReturn(mPublisherLog);
+        when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID)).thenReturn(mSubscriberLog);
+        when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID2)).thenReturn(mSubscriberLog2);
+        when(mStatsService.getVmsClientLogger(NO_SUBSCRIBERS_UID)).thenReturn(mNoSubscribersLog);
 
         mPublisherClient = new MockPublisherClient();
         mPublisherClient2 = new MockPublisherClient();
diff --git a/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java b/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java
index a18c88f..9bdcaa6 100644
--- a/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java
@@ -25,7 +25,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.car.stats.VmsClientLog.ConnectionState;
+import com.android.car.stats.VmsClientLogger.ConnectionState;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -84,66 +84,66 @@
 
     @Test
     public void testLogConnectionState_Connecting() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.CONNECTING);
         validateConnectionStats("10101,test.package,1,0,0,0,0");
     }
 
     @Test
     public void testLogConnectionState_Connected() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.CONNECTED);
         validateConnectionStats("10101,test.package,0,1,0,0,0");
     }
 
     @Test
     public void testLogConnectionState_Disconnected() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.DISCONNECTED);
         validateConnectionStats("10101,test.package,0,0,1,0,0");
     }
 
     @Test
     public void testLogConnectionState_Terminated() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.TERMINATED);
         validateConnectionStats("10101,test.package,0,0,0,1,0");
     }
 
     @Test
     public void testLogConnectionState_ConnectionError() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.CONNECTION_ERROR);
         validateConnectionStats("10101,test.package,0,0,0,0,1");
     }
 
     @Test
     public void testLogConnectionState_UnknownUID() {
-        mCarStatsService.getVmsClientLog(-1)
+        mCarStatsService.getVmsClientLogger(-1)
                 .logConnectionState(ConnectionState.CONNECTING);
         testEmptyStats();
     }
 
     @Test
     public void testLogConnectionState_MultipleClients_MultipleStates() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.CONNECTING);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.CONNECTED);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.DISCONNECTED);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logConnectionState(ConnectionState.CONNECTED);
 
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logConnectionState(ConnectionState.CONNECTING);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logConnectionState(ConnectionState.CONNECTED);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logConnectionState(ConnectionState.TERMINATED);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logConnectionState(ConnectionState.CONNECTING);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logConnectionState(ConnectionState.CONNECTION_ERROR);
         validateConnectionStats(
                 "10101,test.package,1,2,1,0,0\n"
@@ -152,18 +152,18 @@
 
     @Test
     public void testLogPacketSent() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER, 5);
         validateClientStats("10101,1,2,3,5,1,0,0,0,0");
     }
 
     @Test
     public void testLogPacketSent_MultiplePackets() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER, 1);
 
         validateClientStats("10101,1,2,3,6,3,0,0,0,0");
@@ -171,11 +171,11 @@
 
     @Test
     public void testLogPacketSent_MultipleLayers() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER2, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER3, 1);
 
         validateClientStats(
@@ -186,11 +186,11 @@
 
     @Test
     public void testLogPacketSent_MultipleClients() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketSent(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketSent(LAYER2, 1);
 
         validateDumpsys(
@@ -203,18 +203,18 @@
 
     @Test
     public void testLogPacketReceived() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER, 5);
         validateClientStats("10101,1,2,3,0,0,5,1,0,0");
     }
 
     @Test
     public void testLogPacketReceived_MultiplePackets() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER, 1);
 
         validateClientStats("10101,1,2,3,0,0,6,3,0,0");
@@ -222,11 +222,11 @@
 
     @Test
     public void testLogPacketReceived_MultipleLayers() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER2, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER3, 1);
 
         validateClientStats(
@@ -237,11 +237,11 @@
 
     @Test
     public void testLogPacketReceived_MultipleClients() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketReceived(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketReceived(LAYER2, 1);
 
         validateDumpsys(
@@ -254,18 +254,18 @@
 
     @Test
     public void testLogPacketDropped() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER, 5);
         validateClientStats("10101,1,2,3,0,0,0,0,5,1");
     }
 
     @Test
     public void testLogPacketDropped_MultiplePackets() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER, 1);
 
         validateClientStats("10101,1,2,3,0,0,0,0,6,3");
@@ -273,11 +273,11 @@
 
     @Test
     public void testLogPacketDropped_MultipleLayers() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER2, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER3, 1);
 
         validateClientStats(
@@ -288,11 +288,11 @@
 
     @Test
     public void testLogPacketDropped_MultipleClients() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketDropped(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketDropped(LAYER2, 1);
 
         validateDumpsys(
@@ -305,21 +305,21 @@
 
     @Test
     public void testLogPackets_MultipleClients_MultipleLayers_MultipleOperations() {
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketSent(LAYER, 3);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketReceived(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID)
                 .logPacketDropped(LAYER, 1);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketReceived(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketReceived(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketReceived(LAYER, 2);
-        mCarStatsService.getVmsClientLog(CLIENT_UID2)
+        mCarStatsService.getVmsClientLogger(CLIENT_UID2)
                 .logPacketSent(LAYER2, 2);
-        mCarStatsService.getVmsClientLog(-1)
+        mCarStatsService.getVmsClientLogger(-1)
                 .logPacketDropped(LAYER2, 12);
 
 
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
index e3dcb50..e1c9d9a 100644
--- a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
@@ -63,8 +63,8 @@
 import com.android.car.VmsPublisherService;
 import com.android.car.hal.VmsHalService;
 import com.android.car.stats.CarStatsService;
-import com.android.car.stats.VmsClientLog;
-import com.android.car.stats.VmsClientLog.ConnectionState;
+import com.android.car.stats.VmsClientLogger;
+import com.android.car.stats.VmsClientLogger.ConnectionState;
 import com.android.car.user.CarUserService;
 
 import org.junit.After;
@@ -151,13 +151,13 @@
     private ArgumentCaptor<ServiceConnection> mConnectionCaptor;
 
     @Mock
-    private VmsClientLog mSystemClientLog;
+    private VmsClientLogger mSystemClientLog;
     @Mock
-    private VmsClientLog mUserClientLog;
+    private VmsClientLogger mUserClientLog;
     @Mock
-    private VmsClientLog mUserClientLog2;
+    private VmsClientLogger mUserClientLog2;
     @Mock
-    private VmsClientLog mHalClientLog;
+    private VmsClientLogger mHalClientLog;
 
     private VmsClientManager mClientManager;
 
@@ -176,7 +176,7 @@
         mSystemServiceInfo.applicationInfo.uid = TEST_APP_ID;
         when(mPackageManager.getServiceInfo(eq(SYSTEM_CLIENT_COMPONENT), anyInt()))
                 .thenReturn(mSystemServiceInfo);
-        when(mStatsService.getVmsClientLog(TEST_SYSTEM_UID)).thenReturn(mSystemClientLog);
+        when(mStatsService.getVmsClientLogger(TEST_SYSTEM_UID)).thenReturn(mSystemClientLog);
 
         mUserServiceInfo = new ServiceInfo();
         mUserServiceInfo.permission = Car.PERMISSION_BIND_VMS_CLIENT;
@@ -184,10 +184,10 @@
         mUserServiceInfo.applicationInfo.uid = TEST_APP_ID;
         when(mPackageManager.getServiceInfo(eq(USER_CLIENT_COMPONENT), anyInt()))
                 .thenReturn(mUserServiceInfo);
-        when(mStatsService.getVmsClientLog(TEST_USER_UID)).thenReturn(mUserClientLog);
-        when(mStatsService.getVmsClientLog(TEST_USER_UID_U11)).thenReturn(mUserClientLog2);
+        when(mStatsService.getVmsClientLogger(TEST_USER_UID)).thenReturn(mUserClientLog);
+        when(mStatsService.getVmsClientLogger(TEST_USER_UID_U11)).thenReturn(mUserClientLog2);
 
-        when(mStatsService.getVmsClientLog(Process.myUid())).thenReturn(mHalClientLog);
+        when(mStatsService.getVmsClientLogger(Process.myUid())).thenReturn(mHalClientLog);
 
         when(mResources.getInteger(
                 com.android.car.R.integer.millisecondsBeforeRebindToVmsPublisher)).thenReturn(